状态压缩DP 之 poj 2686

第一次做状态压缩DP,之前敲了一个 “旅行商问题” ,对状态压缩DP,有了一定了解,对此题的理解和解决有很大的帮助。

//  [4/29/2014 Sjm]
/*
 
状态压缩: 针对集合的DP。
 
题意: 
旅行家从 a 出发,此时有 S 张车票,为到达 b,求花费最短的时间。
 
分析: 
假设"在 v 点时,旅行商有 S 张票",
每到达与 a 相邻的国家,需要用掉一张车票i,所到达的国家设为 u,
此时"在 u 点时, 旅行商有 S\{i} 张票",
再到达与 u 相邻的国家,以此类推.....直至到达 b 国家。
 
总结:
在分析中可以看到状态的转换:
     "在 v 点时,旅行商有 S 张票"  ----->  在 u 点时, 旅行商有 S\{i} 张票
而转移的开销是: (两点间距离)/ (马匹的数目)。
(可以将上述过程看成建图过程,状态即顶点,转移即边,转移的开销即边的权值)
由于 S(即车票)是集合,故而考虑状态压缩DP解决。
 
综上:
状态:
dp[S][v] := 当此时所到达点为 v并且 所剩票数为 S 时,所需要的最小花费
决策:
dp[S & ~(1<<i)][u] = min(dp[S & ~(1<<i)][u], dp[S][v] + (double)d[v][u] / myT[i])
 
*/
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <algorithm>
 5 using namespace std;
 6 const int MAX_N = 8, MAX_M = 30, INF = 0x3f3f3f3f;
 7 
 8 int n, m, p, a, b;
 9 int myT[MAX_N];  // 马匹数
10 int d[MAX_M][MAX_M];  // 各国家间道路的距离(-1表示没有道路)
11 double dp[1 << MAX_N][MAX_M];
12 
13 void Solve()
14 {
15     double ans = 1.0 * INF;
16     for (int i = 0; i < 1 << n; i++)
17         fill(dp[i], dp[i] + m, INF);
18     dp[(1 << n) - 1][a - 1] = 0;
19     for (int S = (1 << n) - 1; S >= 0; S--) {
20         ans = min(ans, dp[S][b - 1]);
21         for (int v = 0; v < m; v++) {
22             for (int i = 0; i < n; i++) {
23                 if (S >> i & 1) {
24                     for (int u = 0; u < m; u++) {
25                         if (d[v][u] >= 0) {
26                             // 使用车票 i, 从 v 移动到 u。
27                             dp[S & ~(1 << i)][u] = min(dp[S & ~(1 << i)][u], dp[S][v] + (double)d[v][u] / myT[i]);
28                         }
29                     }
30                 }
31             }
32         }
33     }
34     if (INF == ans) printf("Impossible\n");
35     else printf("%.3f\n", ans);
36 }
37 
38 int main()
39 {
40     //freopen("input.txt", "r", stdin);
41     //freopen("output.txt", "w", stdout);
42     while (scanf("%d %d %d %d %d", &n, &m, &p, &a, &b) && (n || m || p || a || b)) {
43         for (int i = 0; i < n; i++)
44             scanf("%d", &myT[i]);
45         memset(d, -1, sizeof(d));
46         for (int i = 0; i < p; i++) {
47             int x, y, z;
48             scanf("%d %d %d", &x, &y, &z);
49             d[x-1][y-1] = d[y-1][x-1] = z;
50         }
51         Solve();
52     }
53     return 0;
54 }

 



 

posted @ 2014-04-29 17:53  JmingS  阅读(218)  评论(0编辑  收藏  举报