题意:给定连通图,求出连通图的所有子图的颜色数。 一个图的颜色数,指最少的颜色数,给图染色,使得有边相邻的点之间颜色不同。
思路:首先想法是DFS枚举,然后计算颜色,发现对于给定图,求颜色不会求? 毕竟是很乱的无向图。
那么考虑DP:dp[s]=min(dp[s0]+1),s0是s的子集,且满足s^s0是独立集。 那么复杂度是O(3^N);
因为有补集,还可以用反演DP???我第一次遇到。好菜啊,有机会补一下。
#include<bits/stdc++.h> #define uint unsigned int #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1000010; char c[20][20]; bool vis[maxn]; int q[maxn],tot,N; uint dp[maxn]; void check(int S) { rep(i,0,S) vis[i]=0,dp[i]=1000000000; dp[0]=0; rep(i,0,S) { tot=0; bool F=1; rep(j,0,N-1) if(i&(1<<j)) q[++tot]=j; rep(j,1,tot){ if(!F) break; rep(k,1,tot) if(c[q[j]][q[k]]=='1') { F=0; break; } } if(F) vis[i]=1; } } int main() { int T,S; scanf("%d",&T); while(T--){ scanf("%d",&N); S=(1<<N)-1; rep(i,0,N-1) scanf("%s",c[i]); check(S); for(int s=1;s<=S;s++){ for(int i=s;;i=(i-1)&s){ if(vis[i^s]){ dp[s]=min(dp[s],dp[i]+1); } if(i==0) break; } } uint t=1,ans=0; for(int i=1;i<=S;i++){ t=t*233; ans+=t*dp[i]; } cout<<ans<<endl; } return 0; }