本题课抽象成给出一些集合,求最多能有多少组集合,使每组的并集是全集。这里面每个集合就是每个点以及和他们邻近的点。
点最多有16个所以想到用2进制压缩。
首先在输入时用二进制记录下每个节点及邻接的节点的集合a[i]。
然后枚举这些节点的组合(同样用二进制的方法)
对于这些组合进行dp,dp的转移:设S是一个集合,S0是它的子集且并集是全集,dp[S]=max(dp[S0])+1
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int N;
int dp[66000];
int Cov[66000];
int a[66000];
int main(){
int kase=1;
while(~scanf("%d",&N)){
if(!N) break;
int ALL=(1<<N)-1;
for(int i=0;i<N;i++){
int m;
scanf("%d",&m);
a[i]=1<<i;
for(int j=1;j<=m;j++){
int t;
scanf("%d",&t);
a[i]|=(1<<t);
}
}
memset(dp,0,sizeof(dp));
for(int i=0;i<(1<<N);i++){
Cov[i]=0;
for(int j=0;j<N;j++){
if(i&(1<<j)){
Cov[i]|=a[j];
}
}
}
for(int i=1;i<(1<<N);i++){
if(Cov[i]==ALL){
for(int j=i;j;j=(j-1)&i){
if(Cov[j]==ALL) dp[i]=max(dp[i],dp[i^j]+1);
}
}
}
printf("Case %d: %d\n",kase++,dp[ALL]);
}
return 0;
}