Poetize11的T3

蒟蒻非常欢脱的写完了费用流,发现。。。边的cost竟然只算一次!!!

然后就跪了。。。

Orz题解:"类型:Floyd传递闭包+最小生成树+状态压缩动态规划
首先Floyd传递闭包,然后找出所有∑ai =0的集合,对每个集合求出最小生成树,就是该集合内部能量转化的最小代价。
然后把每个集合当做一个物品,做一遍类似背包的DP。DP过程中F[i]表示二进制状态为i(1表示该点选了,0表示没选)时已选的点之间能量转化的最小代价。然后枚举所有的j,如果i and j=0,那么用F[i]+F[j]更新一下F[i or j]。
直接这样DP可能会超时,我们不妨去除一些诸如ai=0之类的点。然后把∑ai=0的集合存进数组,DP时只循环数组内的状态来加速。"

原来Floyd还有如此妙用= =

 

 1 /**************************************************************
 2     Problem: 3058
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:36 ms
 7     Memory:1580 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <cstring>
12 #include <algorithm>
13  
14 using namespace std;
15 const int N = 20, M = 65536;
16  
17 int n, m, p, q, l, t;
18 int a[N], d[N][N], g[N], b[M], c[N], f[M], s[M];
19 bool vis[N];
20  
21 inline int read() {
22     int x = 0, sgn = 1;
23     char ch = getchar();
24     while (ch < '0' || '9' < ch) {
25         if (ch == '-') sgn = -1;
26         ch = getchar();
27     }
28     while ('0' <= ch && ch <= '9') {
29         x = x * 10 + ch - '0';
30         ch = getchar();
31     }
32     return sgn * x;
33 }
34  
35 int prim() {
36     int res = 0, i, j, k, tmp;
37     memset(vis, 0, sizeof(vis));
38     memset(g, 0x3f, sizeof(g));
39     g[c[1]] = 0;
40     for (i = 1; i <= m; ++i) {
41         tmp = 0x3fffffff;
42         for (j = 1; j <= m; ++j)
43             if (!vis[c[j]] && g[c[j]] < tmp) tmp = g[c[j]], k = c[j];
44         if (tmp == 0x3f3f3f3f) return -1;
45         res += tmp;
46         vis[k] = 1;
47         for (j = 1; j <= m; ++j)
48             if (!vis[c[j]] && g[c[j]] > d[k][c[j]])
49                 g[c[j]] = d[k][c[j]];
50     }
51     return res;
52 }
53  
54 void Floyd() {
55     int i, j, k;
56     for (k = 1; k <= n; ++k)
57         for (i = 1; i <= n; ++i)
58             for (j = 1; j <= n; ++j)
59                 d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
60 }
61  
62 int main() {
63     int i, j, k, x, y, maxi;
64     n = read(), m = read();
65     memset(d, 0x3f, sizeof(d));
66     t = (1 << n) - 1;
67     for (i = 1; i <= n; ++i) {
68         if (!(a[i] = read())) t ^= 1 << i - 1;
69         d[i][i] = 0;
70     }
71     for (i = 1; i <= m; ++i) {
72         x = read() + 1, y = read() + 1;
73         d[x][y] = d[y][x] = read();
74     }
75     Floyd();
76     memset(f, 0x3f, sizeof(f));
77     f[0] = 0;
78     for (p = i = 0, maxi = 1 << n; i < maxi; ++i) {
79         for (j = 0; j < n; ++j)
80             if ((i >> j & 1) && !a[j + 1]) break;
81         if (j < n) continue;
82         b[i] = 0;
83         for (m = j = 0; j < n; ++j)
84             if (i >> j & 1) b[i] += a[j + 1], c[++m] = j + 1;
85         if (b[i]) continue;
86         b[i] = prim();
87         s[++p] = i;
88     }
89     for (q = 2; q <= p; ++q) {
90         i = s[q], k = b[i];
91         if (k == -1) continue;
92         for (l = 1; l <= p; ++l) {
93             j = s[l];
94             if (!(i & j)) f[i | j] = min(f[i | j], f[j] + k);
95         }
96     }
97     if (f[t] == 0x3f3f3f3f) puts("Impossible");
98     else printf("%d\n", f[t]);
99 }
View Code

 

posted on 2014-11-23 21:46  Xs酱~  阅读(366)  评论(0编辑  收藏  举报