color II
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 62 Accepted Submission(s): 15
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 ∑2n−1id(S)=1fid(S)×233id(S)mod232 .
Sample Input
2
4
0110
1010
1101
0010
4
0111
1010
1101
1010
Sample Output
1022423354
2538351020
Hint
For the first test case, ans[1..15]= {1, 1, 2, 1, 2, 2, 3, 1, 1, 1, 2, 2, 2, 2, 3}
Author
学军中学
Source
2016 Multi-University Training Contest 8
Recommend
wange2014 | We have carefully selected several similar problems for you: 5831 5830 5829 5828 5827
题意:
求公式
∑2n−1id(S)=1fid(S)×233id(S)mod232.
其中
fid(S)
为点集s二进制状压下的十进制数表示,
fid(S)
为由点集s构成的子图最少需要的颜色数,使得对每个点涂色后相邻点不重色。
解:
对于集合s,最少的涂色种数dp[s]= min{dp[s-s0]+1 };
(s0为s的非空子集,并且s0内的点互不相连,你说是不是?)
实际上就是状态转移时,每次考虑的都是一套新颜色的点集。
时间复杂度
O(n3)
证明:
O(∑nk=0C(n,k)∗2k)=O((1+2)n)=O(3n)
(二项式定理)
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<cmath>
#define ysk(x) (1<<(x))
using namespace std;
const int INF=1e9+7;
const double eps=1e-7;
const int maxn=18;
const int maxS=262144;
typedef long long ll;
const ll mod=((ll)1<<32) ;
const ll Xmod=((ll)1<<32)-1 ;
ll pre[maxS+10] ;//pre[x]=233^(id(S))%mod
int n,ed;//点数,n个点下的最大状态
bool G[maxn+5][maxn+5];//邻接矩阵
bool no_edge_inside[maxS+5];//如果值为1 ,表示没有边使当前点集中的点相连
ll dp[maxS+5];
int lowbit(int x)
{
return x&(-x);
}
int getId(int s)//得到单个元素的点集中元素编号
{
int cnt=-1;
while(s)
{
s>>=1;
cnt++;
}
return cnt;
}
void find_no_edge_inside()//枚举点集,判断点集内的点是否有边相连。
{
ed=ysk(n)-1;
memset(no_edge_inside,0,(ed+1)*sizeof no_edge_inside[0]);
no_edge_inside[0]=1;
for(int s=1;s<=ed;s++)
{
int ns=lowbit(s);
int s2=s^ns;
int i=getId(ns);
no_edge_inside[s]=no_edge_inside[s2];
if(!no_edge_inside[s]) continue;
for(int j=0;j<n;j++) if( ysk(j)&s2 )
{
if(G[i][j])
{
no_edge_inside[s]=0;
break;
}
}
}
}
void getPre()
{
pre[0]=1;
for(int i=1;i<=maxS;i++)
{
pre[i]=(pre[i-1]*233)&Xmod;
}
}
void solve()//状压dp
{
dp[0]=0;
for(int s=1;s<=ed;s++)
{
dp[s]=INF;
for(int s0=s;s0;s0=(s0-1)&s)
{
if(no_edge_inside[s0])
dp[s]=min(dp[s],dp[s-s0]+1);
}
}
ll ans=0;
for(int s=1;s<=ed;s++)
{
ans=(ans+ (dp[s]*pre[s]&Xmod))&Xmod;
}
printf("%lld\n",ans);
}
int main()
{
getPre();
int T;scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
char ch;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf(" %c",&ch);
if(ch=='0') G[i][j]=0;
else G[i][j]=1;
}
}
find_no_edge_inside();
solve();
}
return 0;
}