题目的意思是有n台服务器运行着n类程序,一个黑客有n中类的病毒,最多每台服务器可以放一种病毒,但是相邻的服务器会感染同种病毒,只暂停一种服务,问能够暂停的程序的最大种数。
解决的方法是,用位表示集合,问题的答案相当于是求出最多集合的组合,组合内的集合并集是全集。求这些组合最大的数目。转移方程式f[s]={f[s^s0],s0这种组合内的集合并集是全集}+1.
这里涉及到一些集合的操作:
或运算,将元素加入到集合之中。
枚举集合的所有组合的可能性:
for(int i=0;i<(1<<n);i++)
{
for(int j=0;j<n;j++)
{
if(i&(1<<n))cover[i]=cover[i]|s[j];
}
}
枚举集合s的所有子集
for(int i=s;i>0;i=(i-1)&s)
{
//insert code
}
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 1<<17
int cover[MAXN];
int s[20];
int f[MAXN];
int main()
{
int n;
int kas=0;
while(scanf("%d",&n),n)
{
memset(s,0,sizeof(s));
for(int i=0;i<n;i++)
{
int m;cin>>m;
s[i]=s[i]|(1<<i);
for(int j=0;j<m;j++)
{
int t;cin>>t;
s[i]=s[i]|(1<<t);
}
}
memset(cover,0,sizeof(cover));
for(int i=0;i<(1<<n);i++)
{
for(int j=0;j<n;j++)
{
if(i&(1<<j))cover[i]=cover[i]|s[j];
}
}
memset(f,0,sizeof(f));
for(int i=0;i<(1<<n);i++)
{
for(int j=i;j>0;j=(j-1)&i)
{
if(cover[j]==(1<<n)-1)
{
f[i]=max(f[i],f[i^j]+1);
}
}
}
printf("Case %d: %d\n",++kas,f[(1<<n)-1]);
}
}