网站改版 程序变了 原来的文章内容链接地址 打不开怎么办/站长推荐入口自动跳转
原题链接
题目大意
有一个旅行家计划乘马车旅行。他所在的国家里共有 mmm 个城市,在城市之间有若干道路相连。从某个城市沿着某条道路到相邻的城市需要乘坐马车。而乘坐马车需要使用车票,每用一张车票只可以通过一条道路。每张车票上都记有马的匹数,从一个城市移动到另一个城市
的所需时间等于城市之间道路的长度除以马的数量的结果。这位旅行家一共有nnn张车票,第iii张车票上的马的匹数是tit_iti, 一张车票只能使用一次,并且换乘所需要的时间可以忽略。求从城市 aaa 到城市 bbb所需要的最短时间。如果无法到达城市 bbb 则输出"Impossible"。
思路:状态压缩+DAG的最短路
所谓状态压缩即简介,之前我写过旅行商问题的状态压缩DP的解法,该问题与旅行商问题大相径庭。不过应该压缩何种状态,DP的状态转移方程式都是值得思考的问题。
拿到题看得出来是一道最短路的问题 我看到图就感觉是最短路的问题,但是车票是一个限制因素,单纯的迪杰斯特拉是不能解决的。很可能真实的最短路要通过的路径数目比车票数目还多,而且不知道哪里应该使用哪张车票,我有一个大胆的想法,以车票作为约束,我们分别寻找只使用一张车票,使用两张车票,。。使用nnn张车票分别的最短路径,然后越长的路给越多马匹的车票,最后在这nnn种情况取用时最少的。这样的思路感觉已经比较接近答案了 ,看了一眼题解,还是状态压缩比较短小精悍
我们用整数表示目前剩余的车票集合,dp[S][u]dp[S][u]dp[S][u]表示剩余车票集合为SSS的情况下,到达节点uuu所需要的时间。那么状态转移的话,就是使用SSS中的一张车票iii,到达uuu的临近点vvv,该状态转移所需要的花费是d[u][v]/t[i]d[u][v]/t[i]d[u][v]/t[i],这样讲车票集合从多到少进行枚举,不断进行状态转移,就可以求出最终结果,具体步骤见代码注释
这样做的结果是将所有的城市/车票组合都构建成了一张图从起点开始不断向外扩张,比如t={1,3}t=\{1,3\}t={1,3},道路网如下,从2到1
AC代码
#include<iostream>
#include<iomanip>
#include<string.h>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;#define ll int
#define MaxN 10
#define MaxM 35
#define inf 222222222ll n, m, p, a, b, t[MaxN], d[MaxM][MaxM];
double dp[1 << MaxN][MaxM], res = inf;//dp[S][i]:剩余船票集合为S的情况下,走到i点需要的时间
int main() {while (cin >> n >> m >> p >> a >> b){if (n == 0 && m == 0 && p == 0 && a == 0 && b == 0)return 0;res = inf; memset(d, -1, sizeof(d));//初始化for (ll i = 0; i < n; i++)cin >> t[i];for (ll i = 1; i <= p; i++) {ll a, b, c; cin >> a >> b >> c;d[a][b] = c; d[b][a] = c;}for (ll s = 0; s < 1 << n; s++)for (ll k = 1; k <= m; k++)dp[s][k] = inf;dp[(1 << n) - 1][a] = 0;//不用船票,到a用时为0.//从多到少依次枚举集合for (ll s = (1 << n) - 1; s >= 0; s--) {res = min(res, dp[s][b]);for (ll v = 1; v <= m; v++) {//每个点for (ll tmp = 0; tmp <= n; tmp++) {//每个车票if (s >> tmp & 1) {//该车票属于集合S,也就是车票尚未使用for (ll u = 1; u <= m; u++) {//每个车票都有机会用来更新他的临近点if (d[v][u] >= 0) {//v可以到udp[s&~(1 << tmp)][u] = min(dp[s&~(1 << tmp)][u], dp[s][v] + 1.0*d[v][u] / t[tmp]);}}}}}}if (res == inf) cout << "Impossible" << endl;else cout << res << endl;}
}