zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    poj3278 Catch That Cow
    poj2251 Dungeon Master
    poj1321 棋盘问题
    poj3083 Children of the Candy Cor
    jvm基础知识—垃圾回收机制
    jvm基础知识1
    java面试基础必备
    java soket通信总结 bio nio aio的区别和总结
    java scoket aIO 通信
    java scoket Blocking 阻塞IO socket通信四
  • 原文地址:https://www.cnblogs.com/rausen/p/4117526.html
Copyright © 2011-2022 走看看