Hackers' Crackdown
题意就是给你m个集合,求这m个集合最多可以组成多少个全集,全集拥有从1到n所有元素。
很明显的状压dp,以下数字全是二进制,用p数组记录第i个集合中有哪些元素(如第一个元素用1表示,第二个用10,第三个用100,第二个和第三个元素的并集用110表示),然后用cover数组记录某些集合的并集(如cover[101]=111100,表示第一个集合和第三个集合的并集是第3,4,5,6个元素的组成集合),用f数组记录某些集合可以组成全集的个数(f[111]=1,表示第1,2,3个集合最多可以组成1个全集)
#include<stdio.h>
#include<string.h>
#define max(x,y) x>y?x:y
#define N 1<<16
int Kase=0;
int f[N],p[20],cover[N];
int main()
{
int i,n;
while(~scanf("%d",&n)&&n)
{
int m,t,k;
memset(f,0,sizeof(f));
for(k=0;k<n;k++)
{
scanf("%d",&m);
p[k]=1<<k;
for(i=0;i<m;i++)
{
scanf("%d",&t);
p[k]|=(1<<t);
}
}
int ALL=(1<<n)-1;
for(i=1;i<(1<<n);i++)
{
cover[i]=f[i]=0;
for(k=0;k<n;k++)
if(i&(1<<k))
cover[i]|=p[k];
for(k=i;k;k=(k-1)&i)
if(cover[k]==ALL)
f[i]=max(f[i],f[i^k]+1);
}
printf("Case %d: %d\n",++Kase,f[ALL]);
}
}