DAG状压dp的一种
题目:
$m$个城市,$n$张车票,第i张车票上的时间是$t_i$, 求从$a$到$b$的最短时间,如果无法到达则输出“impossible”
解法:
考虑状态:“现在在城市$v$,此时还剩下的车票的集合为$S$”这样的状态。从这个状态出发,使用一张车票移动到$i in S$移动到相邻的城市$u$,就相当于转移到了“在城市$u$,此时还剩下的车票的集合为$S/ { i }$”这个状态。
把这个转移看成一条边,那么边上的花费就是(v-u间道路的长度)/ $t_i$。DAG上的最短路dp就能解。
代码如下:
1 int n, m, a, b, p; 2 int t[MAXN]; 3 int d[MAXM][MAXM]; 4 double dp[1 << 12][MAXM]; 5 6 void solve() { 7 for (int i = 0; i < 1 << n; i++) { 8 fill(dp[i], dp[i] + m, INF); 9 } 10 dp[(1 << n) - 1][a - 1] = 0; 11 double res = INF; 12 for (int S = (1 << n) - 1; S >= 0; S--) { 13 res = min(res, dp[S][b - 1]); 14 for (int v = 0; v < m; v++) { 15 for (int i = 0; i < n; i++) { 16 if (S >> i & 1) { 17 for (int u = 0; u < m; u++) { 18 if (d[v][u] >= 0) { 19 dp[S & ~(1 << i)][u] = 20 min(dp[S & ~(1 << i)][u], 21 dp[S][v] + (double)d[v][u] / t[i]); 22 } 23 } 24 } 25 } 26 } 27 } 28 if (res == INF) { 29 printf("Impossible "); 30 } else { 31 printf("%.3f ", res); 32 } 33 } 34 35 int main() { 36 #ifndef ONLINE_JUDGE 37 freopen("input.txt", "r", stdin); 38 #endif // !ONLINE_JUDGE 39 while (scanf("%d%d%d%d%d", &n, &m, &p, &a, &b) != EOF) { 40 if (p == 0 && m == 0 && n == 0 && a == 0 && b == 0) break; 41 MEM(t, 0), MEM(d, 0), MEM(dp, 0); 42 REP(i, 0, n - 1) scanf("%d", &t[i]); 43 REP(i, 0, MAXM - 1) REP(j, 0, MAXM - 1) d[i][j] = -1; 44 REP(i, 1, p) { 45 int u = READ(), v = READ(), w = READ(); 46 u--, v--; 47 d[u][v] = d[v][u] = w; 48 } 49 solve(); 50 } 51 return 0; 52 }