刚开始刷dp,看了好久才看明白是怎么回事。
首先是题意:有N台电脑,每台电脑有N(N<=16)个服务,一个黑客可以在每台电脑上跑一个(只能跑一个)让一种服务崩溃的病毒,并且这个病毒可以传播到跟他邻接的顶点,问最多这个黑客可以让多少个服务崩溃?(每台电脑上都是N个不同服务,每台电脑上跑的都是一样的服务,让一个服务崩溃是让所有的电脑上的这个服务崩溃)
思路:看书上的,把n个集合p1,p2...分成尽量多组,是得每组中所有集合的并集等于全集。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1<<16;
//p[i]表示计算机i相连的机器的集合,cover[s]表示汝干p[i]的集合s中所有p[i]的并集
//其中s的二进制数表示中的1表示p[i]是否存在这个集合中
int p[20],cover[maxn],f[maxn];
int main()
{//freopen("in.txt","r",stdin);
int n,m;
int x;
int loop=1;
while(cin>>n,n)
{
memset(p,0,sizeof(p));
for(int i=0;i<n;i++)
{
cin>>m;
p[i]=1<<i;
for(int j=0;j<m;j++)
{
cin>>x;
p[i]|=(1<<x);
}
}
for(int s=0;s<(1<<n);s++)
{
cover[s]=0;
for(int i=0;i<n;i++)
if(s&(1<<i))
cover[s]|=p[i];
}
f[0]=0;
int all=(1<<n)-1;
for(int s=1;s<(1<<n);s++)
{
f[s]=0;
//s中可能存在重复的,所以枚举子集
for(int s0=s;s0;s0=(s0-1)&s)
if(cover[s0]==all)
f[s]=max(f[s],f[s^s0]+1);
}
cout<<"Case "<<loop++<<": "<<f[all]<<endl;
}
return 0;
}