题目地址:http://vjudge.net/problem/UVA-11825
题目难在怎么转化
因为题目求的是完全瘫痪,也就是所有的计算机都没有运行
将一个计算机及其相邻的计算机表示成集合A,如第一行的 2 1 2,表示为111
为了使所有的计算机都没有运行,就是求A这种集合任意组合能使 他们交集全为1,如A1=000111,A2=111000,A3=001100,那么000~111总的子集A1|A2=111111全为一,用S= 011表示这种排列,其满足题意的
便是求0~n-1的子集中满足题意的S有几个
直接枚举0~n-1的子集 找出这样的S,再进行DP,f[i] 表示i集合的子集中满足S要求的组合数 f[i]=max{f[i0]+1|i0为i的子集且集合满足S的要求}
还有因为为无向图,所以每组S只看成一个服务的暂停,虽然里面有多个计算机,可以暂停多个服务,但为了不混淆,只看成每组只暂停一个服务,其他的计算机可以看成是别的S组别
#include <bits/stdc++.h>
using namespace std;
#define REP(i,a,b) for(int i=a;i<=(b);++i)
#define REPD(i,a,b) for(int i=a;i>=(b);--i)
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
int A[16],cover[(1<<16)+5],f[(1<<16)+5];
int main(int argc, char const *argv[])
{
int n,kase=0;
while(scanf("%d",&n)==1&&n){
REP(i,0,n-1){ //读入,转化为集合
int m,k;
scanf("%d",&m);
A[i]=1<<i;
while(m--) {scanf("%d",&k); A[i]|=1<<k;}
}
REP(i,1,(1<<n)-1){ //1~n 的任意子集算出 A[]的交集
cover[i]=0;
REP(j,0,n-1) if((1<<j)&i) cover[i]|=A[j];
}
int ALL=(1<<n)-1;
REP(S,1,ALL){
f[S]=0;
for(int S0=S;S0;S0=(S0-1)&S) if(cover[S0]==ALL) f[S]=max(f[S],f[S-S0]+1);
}
printf("Case %d: %d\n", ++kase,f[ALL]);
}
return 0;
}