题意:全集为0, 1, 2, ..., N-1,输入N个子集,求这N个子集最多能分成多少组,使得每组的并集都是全集。
——>>设f[S]为集合S的最大拆分组数。
则对于S的所有子集S0,得状态转移方程:
(若S0的元素并集为全集)
f[S] = max(f[S], f[S^S0]+1);
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 20;
int cover[1<<maxn], f[1<<maxn];
int main()
{
int N, m, i, temp, p[maxn], S, S0, cnt = 1;
while(scanf("%d", &N) == 1 && N)
{
for(i = 0; i < N; i++) //输入N个集合
{
p[i] = 1<<i;
scanf("%d", &m);
while(m--)
{
scanf("%d", &temp);
p[i] |= (1<<temp);
}
}
for(S = 0; S < (1<<N); S++) //求子集所包含的域
{
cover[S] = 0;
for(i = 0; i < N; i++)
if(S & (1<<i)) cover[S] |= p[i];
}
f[0] = 0;
int ALL = (1<<N) - 1;
for(S = 1; S < (1<<N); S++) //dp求解
{
f[S] = 0;
for(S0 = S; S0; S0 = S&(S0-1))
if(cover[S0] == ALL)
f[S] = max(f[S], f[S^S0]+1);
}
printf("Case %d: %d\n", cnt++, f[ALL]);
}
return 0;
}