Problem Description You are given an undirected graph with n vertices
numbered 0 through n-1.Obviously, the vertices have 2^n - 1 non-empty subsets. For a
non-empty subset S, we define a proper coloring of S is a way to
assign each vertex in S a color, so that no two vertices in S with the
same color are directly connected by an edge. Assume we’ve used k
different kinds of colors in a proper coloring. We define the
chromatic number of subset S is the minimum possible k among all the
proper colorings of S.Now your task is to compute the chromatic number of every non-empty
subset of the n vertices.Input First line contains an integer t. Then t testcases follow.
In each testcase: First line contains an integer n. Next n lines each
contains a string consisting of ‘0’ and ‘1’. For 0<=i<=n-1 and
0<=j<=n-1, if the j-th character of the i-th line is ‘1’, then
vertices i and j are directly connected by an edge, otherwise they are
not directly connected.The i-th character of the i-th line is always ‘0’. The i-th character
of the j-th line is always the same as the j-th character of the i-th
line.For all testcases, 1<=n<=18. There are no more than 100 testcases with
1<=n<=10, no more than 3 testcases with 11<=n<=15, and no more than 2
testcases with 16<=n<=18.Output For each testcase, only print an integer as your answer in a
line.This integer is determined as follows: We define the identity number
of a subset S is id(S)=∑v∈S2v. Let the chromatic number of S be
fid(S).You need to output ∑1<=id(S)<=2n−1fid(S)×233id(S)mod232.
状压dp。
对于每个集合,枚举他的子集,如果这个子集之间没有边的话,就可以用剩下的集合的答案+1更新答案。
任何一个集合之间是否有边可以预处理出来。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define LL long long
const LL mod=1LL<<31;
int map[20][20],n,dp[530000];
unsigned int pw[530000];
bool ok[530000];
char s[20];
int main()
{
int i,j,k,p,q,x,y,z,S,maxsize,now,T;
unsigned int ans=0;
scanf("%d",&T);
pw[0]=1;
for (i=1;i<=529989;i++)
pw[i]=pw[i-1]*233;
while (T--)
{
scanf("%d",&n);
memset(map,0,sizeof(map));
for (i=0;i<n;i++)
{
scanf("%s",s);
for (j=0;j<n;j++)
map[i][j]=s[j]-'0';
}
maxsize=(1<<n)-1;
memset(ok,0,sizeof(ok));
for (S=0;S<=maxsize;S++)
{
ok[S]=1;
for (i=0;i<n&&ok[S];i++)
if (S&(1<<i))
for (j=0;j<n&&ok[S];j++)
if (S&(1<<j)&&map[i][j])
ok[S]=0;
}
memset(dp,0x3f,sizeof(dp));
dp[0]=0;
ans=0;
for (S=1;S<=maxsize;S++)
for (now=S;now;now=(S&(now-1)))
if (ok[now])
dp[S]=min(dp[S],dp[S-now]+1);
for (S=1;S<=maxsize;S++)
ans+=pw[S]*dp[S];
cout<<ans<<endl;
}
}