HDU 5823 (状压dp)

Problem color II

题目大意

  定义一个无向图的价值为给每个节点染色使得每条边连接的两个节点颜色不同的最少颜色数。

  对于给定的一张由n个点组成的无向图,求该图的2^n-1张非空子图的价值。

  n <= 18

解题分析

  官方题解:

    直接状压dp就行了,f[S]表示点集S的色数,枚举子集转移(子集是独立集)。这样是3^n的。 一个复杂度更优的做法是把所有独立集都预处理出来,然后作n次or卷积。这样是n^2*2^n的。

  

  枚举子集的子集的时间复杂度是3^n 啊 。 即 sigma( C(n,k) * 2 ^k ) = (1 + 2 ) ^ n = 3 ^ n 。

参考程序

 1 #include <map>
 2 #include <set>
 3 #include <stack>
 4 #include <queue>
 5 #include <cmath>
 6 #include <ctime>
 7 #include <string>
 8 #include <vector>
 9 #include <cstdio>
10 #include <cstdlib>
11 #include <cstring>
12 #include <iostream>
13 #include <algorithm>
14 #include <cassert>
15 #pragma comment(linker,"/STACK:102400000,102400000")
16 using namespace std;
17 
18 #define     N             100008             
19 #define     V             1008
20 #define        E            60008    
21 #define        lson        l,m,rt<<1
22 #define     rson        m,r+1,rt<<1|1
23 #define        clr(x,v)    memset(x,v,sizeof(x));
24 #define        LL            long long 
25 
26 const int    mo    =    1000000007;
27 const int     inf =    0x3f3f3f3f;
28 const int     INF =    2000000000;
29 /**************************************************************************/ 
30 
31 int n;
32 char s[20][20];
33 int id[1<<20];
34 unsigned dp[1<<20];
35 
36 void work(){
37 
38     scanf("%d",&n);
39     for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
40     int lx=1<<n;
41     for (int i=0;i<lx;i++) id[i]=1;
42     for (int i=1;i<lx;i++){
43         int u,v;
44         for (u=n;u>=1;u--) if (i & 1<<u-1) break;
45         if (!id[i- (1 << u-1)]) id[i]=0;
46         for (v=1;v<=n;v++) 
47             if (i & 1 << v-1 && u!=v && s[u][v]=='1')
48                 id[i]=0;
49     }
50     for (int i=0;i<lx;i++) dp[i]=20;
51     dp[0]=0;
52     for (int i=1;i<lx;i++)
53         for (int j=i;j;j=(j-1) & i) if (id[j])  //  枚举 子集的子集  黑科技好强啊 !!
54         {
55             dp[i]=min(dp[i],dp[i-j]+1);
56         }        
57     unsigned res=0,tmp=1;
58     for (int i=1;i<lx;i++){
59         tmp = tmp * 233;
60         res = res + tmp * dp[i];
61     }
62     printf("%u
",res);
63 }
64 
65 int main(){
66     int T;
67     scanf("%d",&T);
68     while (T--) work();
69 }
View Code
原文地址:https://www.cnblogs.com/rpSebastian/p/5762546.html