题目大意
把n个集合P1,P2,P3,…,Pn分成尽量多组,使得每组中所有集合的并集等于全集
考虑状压DP,P[i]表示i集合,cover[i]表示若干集合的并集,不难预处理出cover[i],那么DP方程就很好想了,f(S)=max(f(S-S0)|S0为S的子集,且cover[S0]=全集)+1,这里再次用到子集的枚举
for (int S0=S;S;S0=(S0-1)&S)
还有就是这个算法的复杂度是
n3
,不过我分析不来,先留坑在这里
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=16;
int n,kase,P[maxn],cover[1<<maxn],f[1<<maxn];
void clear()
{
memset(P,0,sizeof(P));
memset(cover,0,sizeof(cover));
memset(f,0,sizeof(f));
}
int main()
{
// freopen("hacker.in","r",stdin);
while (scanf("%d",&n)&&n)
{
clear();
int ALL=(1<<n)-1;
printf("Case %d: ",++kase);
for (int i=0;i<n;i++)
{
int m,x;
scanf("%d",&m);
P[i]=1<<i;
while (m--) scanf("%d",&x),P[i]|=1<<x;
}
for (int S=1;S<=ALL;S++)
for (int i=0;i<n;i++)
if (S&(1<<i)) cover[S]|=P[i];
for (int S=1;S<=ALL;S++)
for (int S0=S;S0;S0=(S0-1)&S)
if (cover[S0]==ALL) f[S]=max(f[S],f[S^S0]+1);
printf("%d\n",f[ALL]);
}
return 0;
}