官方题解:直接状压dp就行了,f[S]表示点集S的色数,枚举子集转移(子集是独立集)。这样是3^n的。
这样就可以过了……(独立集就是点互相没有连边)
学到了一个穷举子集的简便写法
for (int j=i; j; j=(j-1)&i)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 int f[300010],q[20],n,t; 5 bool v[300010]; 6 char a[20][20]; 7 unsigned int d[300010]; 8 9 void dfs(int i,int st,bool ff) 10 { 11 if (i==n) v[st]=ff; 12 else { 13 dfs(i+1,st,ff); 14 if (ff) 15 { 16 for (int j=1; j<=t; j++) 17 if (a[q[j]][i]=='1') {ff=0;break;} 18 } 19 q[++t]=i; 20 dfs(i+1,st|(1<<i),ff); 21 t--; 22 } 23 } 24 25 int main() 26 { 27 int cas; 28 scanf("%d",&cas); 29 d[0]=1; 30 for (int i=1; i<(1<<18); i++) d[i]=d[i-1]*233; 31 while (cas--) 32 { 33 scanf("%d",&n); 34 for (int i=0; i<n; i++) 35 scanf("%s",a[i]); 36 int m=1<<n;t=0; 37 memset(v,0,sizeof(v)); 38 dfs(0,0,1); 39 for (int i=1; i<m; i++) f[i]=n; 40 f[0]=0; 41 for (int i=1; i<m; i++) 42 for (int j=i; j; j=(j-1)&i) 43 if (v[j]) f[i]=min(f[i],f[i-j]+1); 44 unsigned int ans=0; 45 for (int i=1; i<m; i++) ans+=d[i]*f[i]; 46 printf("%u\n",ans); 47 } 48 }