• BZOJ3058 四叶草魔杖


    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
    ", f[t]);
    99 }
    View Code
    By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
  • 相关阅读:
    Gulp插件less的使用
    并行与并发的区别
    原生javascript实现异步的7种方式
    原生JS实现bind()函数
    职责链模式
    Nginx如何启用ETag,提高访问速度
    前端性能优化:配置ETag
    迭代器模式
    JS里关于事件的常被考察的知识点:事件流、事件广播、原生JS实现事件代理
    cdn网络加速
  • 原文地址:https://www.cnblogs.com/rausen/p/4117526.html
Copyright © 2020-2023  润新知