BZOJ3590【状压DP】

来源:互联网 发布:武术软件 编辑:程序博客网 时间:2024/05/01 00:55

转自:http://blog.csdn.net/Lethelody/article/details/45147055

orz大神凯爷


原文

SNOI2013竟然出了一道很有难度的状压DP.实在是出人意料.

而且网上似乎并没有题解.我就来写一篇好了.

HYF菊苣似乎写过这道题的题解.

这道题大意就是:给出一个无向图.求一个权值最小的包含所有点的双联通子图.

定义一些状态:

f[i]:集合状态为i.且使在i中的点双联通的最小权值.

h[i][j][0]:一个端点是j.另一个端点在点集i中的边的最小权值.

h[i][j][1]:一个端点是j.另一个端点在点集i中的边的次小权值.

g[i][j][k].集合状态为i.且使在i中的点构成一条链.两端点分别是j和k的最小权值.

容易发现.一个双联通图.必然是由一个双联通的子图和一条链构成的.那么就可以枚举这条链进行转移.

要注意的是:一个点是一个权值为0的双联通图.同时也是一条权值为0的链.

在转移的时候.如果这条链是一个点.转移方程是:

[html] view plain copy
  1. f[i] = min(f[i], f[t] + g[s][u][u] + h[t][u][0] + h[t][u][1]);  
如果这条链的两端点不同.转移方程是:

[html] view plain copy
  1. f[i] = min(f[i], f[t] + g[s][u][v] + h[t][u][0] + h[t][v][0]);  
先预处理出h和m数组就好了.

关于h数组的处理.直接暴力枚举就可以了.

关于g数组的处理.也是一个状压DP.枚举当前点集i能转移出的状态更新就好了.

[cpp] view plain copy
  1. #include <cstdio>  
  2. #include <cstdlib>  
  3. #include <cstring>  
  4. #include <cmath>  
  5. #include <ctime>  
  6. #include <algorithm>  
  7. #include <iostream>  
  8. #include <fstream>  
  9. #include <vector>  
  10. #include <queue>  
  11. #include <deque>  
  12. #include <map>  
  13. #include <set>  
  14. #include <string>  
  15. #define make make_pair  
  16. #define fi first  
  17. #define se second  
  18.    
  19. using namespace std;  
  20.    
  21. typedef long long ll;  
  22. typedef unsigned long long ull;  
  23. typedef pair<int,int> pii;  
  24.    
  25. const int maxn = 20;  
  26. const int maxm = 10100;  
  27. const int maxs = 26;  
  28. const int inf = 1 << 28;  
  29. const int P = 1000000007;  
  30. const double error = 1e-9;  
  31.    
  32. inline int read()  
  33. {  
  34.     int x = 0, f = 1; char ch = getchar();  
  35.     while (ch <= 47 || ch >= 58)  
  36.         f = (ch == 45 ? -1 : 1), ch = getchar();  
  37.     while (ch >= 48 && ch <= 57)  
  38.         x = x * 10 + ch - 48, ch = getchar();  
  39.     return x * f;  
  40. }  
  41.    
  42. struct edge  
  43. {  
  44.     int u, v, w, next;  
  45. } e[maxm];  
  46.    
  47. int n, m, cnt, head[maxn], bin[maxn],  
  48.     f[maxm], g[maxm][maxn][maxn], h[maxm][maxn][2];  
  49.    
  50. void insert(int u, int v, int w)  
  51. {  
  52.     e[cnt] = (edge) {u, v, w, head[u]}, head[u] = cnt++;  
  53.     e[cnt] = (edge) {v, u, w, head[v]}, head[v] = cnt++;  
  54. }     
  55.    
  56. int fac(int x)  
  57. {  
  58.     int ans = 1;  
  59.     for (x = x & (x - 1); x; x = x & (x - 1))  
  60.         ans++;  
  61.     return ans;  
  62. }  
  63.    
  64. void init()  
  65. {  
  66.     for (int i = 0; i < (1 << n); i++)  
  67.         for (int j = 0; j <= n; j++)  
  68.             for (int k = 0; k <= n; k++)  
  69.                 g[i][j][k] = inf;  
  70.    
  71.     for (int i = 1; i <= n; i++) {  
  72.         bin[i] = 1 << (i - 1);  
  73.         g[bin[i]][i][i] = 0;  
  74.     }  
  75.    
  76.     for (int i = 0; i < cnt; i++) {  
  77.         int u = e[i].u, v = e[i].v, s = bin[u] + bin[v];  
  78.         g[s][u][v] = min(g[s][u][v], e[i].w);  
  79.     }  
  80.    
  81.     for (int i = 1; i < (1 << n); i++)  
  82.         for (int u = 1; u <= n; u++)  
  83.             for (int v = 1; v <= n; v++)  
  84.                 if ((bin[u] | i) == i && (bin[v] | i) == i)  
  85.         for (int k = head[v]; k != -1; k = e[k]. next) {  
  86.             int fv = e[k].v;  
  87.             if ((bin[fv] | i) != i) {  
  88.                 int s = i + bin[fv];  
  89.                 g[s][u][fv] = min(g[s][u][fv], g[i][u][v] + e[k].w);  
  90.             }  
  91.         }  
  92.   
  93.     for (int i = 0; i < (1 << n); i++)  
  94.         for (int j = 0; j <= n; j++)  
  95.             for (int k = 0;k <= 1; k++)  
  96.                 h[i][j][k] = inf;  
  97.    
  98.     for (int i = 1; i < (1 << n); i++)  
  99.         for (int u = 1; u <= n; u++)   
  100.             if ((bin[u] | i) != i)  
  101.                 for (int j = head[u]; j != -1; j = e[j].next) {  
  102.                     int v = e[j].v;  
  103.                     if ((bin[v] | i) == i) {  
  104.                         if (e[j].w <= h[i][u][0]) {  
  105.                             h[i][u][1] = h[i][u][0];  
  106.                             h[i][u][0] = e[j].w;  
  107.                         }  
  108.                         else if (e[j].w < h[i][u][1])  
  109.                             h[i][u][1] = e[j].w;  
  110.                     }         
  111.                 }  
  112. }  
  113.    
  114. int work()  
  115. {  
  116.     for (int i = 1; i < (1 << n); i++)  
  117.         f[i] = inf;  
  118.        
  119.     for (int i = 1; i <= n; i++)  
  120.         f[bin[i]] = 0;  
  121.    
  122.     for (int i = 1; i < (1 << n); i++)  
  123.         if (fac(i) >= 2)  
  124.             for (int s = i & (i - 1); s; s = (s - 1) & i) {  
  125.                 int t = i - s;  
  126.                 for (int u = 1; u <= n; u++)  
  127.                     for (int v = 1; v <= n; v++)  
  128.         if ((bin[u] | s) == s && (bin[v] | s) ==s) {  
  129.             if (u == v)  
  130.                 f[i] = min(f[i], f[t] + g[s][u][u] + h[t][u][0] + h[t][u][1]);  
  131.             else  
  132.                 f[i] = min(f[i], f[t] + g[s][u][v] + h[t][u][0] + h[t][v][0]);  
  133.         }  
  134.             }  
  135. }  
  136.    
  137. int main()  
  138. {  
  139.     int t = read();  
  140.    
  141.     while (t--) {  
  142.         n = read(), m = read();  
  143.            
  144.         memset(head, - 1, sizeof head);  
  145.        
  146.         cnt = 0;  
  147.    
  148.         for (int i = 1; i <= m; i++) {  
  149.             int u = read(), v = read(), w = read();  
  150.             insert(u, v, w);  
  151.         }  
  152.    
  153.         init(), work();  
  154.    
  155.         if (f[(1 << n) - 1] < inf)  
  156.             printf("%d\n", f[(1 << n) - 1]);  
  157.         else  
  158.             printf("impossible\n");  
  159.     }  
  160.    
  161.     return 0;  
  162. }  

0 0