http://acm.hdu.edu.cn/showproblem.php?pid=5823
给你一个无向图,然后要枚举所有点的子集的最小染色方案数,然后输出 ∑ans[i]*233^i mod 2^32;
n<=18
我们先预处理出所有的独立集 2^n*n*n
枚举每一个子集,对于这个子集(k个点)我们要求它的最小染色方案数的复杂度是2^k:
对于当前子集state,去枚举其所有的子集S2,先判断是否为一个独立集,如果是,则dp[state]=min(dp[state],dp[S2^state]+1);
因为染色=划分独立集,最优解一定是若干个独立集
而我们枚举了所有的独立集,这样得到的答案必然是最优解。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <bitset>
#include <iostream>
using namespace std;
const int maxn = 18;
int dp[1<<maxn];
bool d[1<<maxn];
int G[maxn][maxn];
char ss[maxn+10];
int vis[maxn];
int main()
{
//freopen("input.txt","r",stdin);
int tt;
scanf("%d",&tt);
while (tt--)
{
int n;
cin>>n;
getchar();
for (int i=0; i<n; i++)
{
gets(ss);
for (int j=0;j<n;j++)
if (ss[j]=='1')
G[i][j]=1;
else G[i][j]=0;
}
int all=1<<n;
for (int state=1;state<all;state++)
{
memset(vis,0,sizeof vis);
for (int j=0;j<n;j++)
if (state&(1<<j))vis[j]=1;
int flag=1;
for (int j=0;j<n;j++)
{
for (int k=0;k<n;k++)
{
if (vis[j]&&vis[k]&&G[j][k])
{
flag=0;break;
}
}
if (!flag)break;
}
d[state]=flag;
}
dp[0]=0;
for (int state=1;state<all;state++)
{
dp[state]=1e8;
for (int state2=state;state2;state2=(state2-1)&state)
if (d[state2])
dp[state]=min(dp[state],dp[state2^state]+1);
}
unsigned xi=233,ans=0;
for (int i=1;i<all;i++)
ans+= xi*dp[i],xi*=233;
printf("%u\n",ans);
}
return 0;
}