参考:https://blog.csdn.net/sinat_30062549/article/details/51292353
求出有多少个全集包含所有电脑;
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const double epos=1e-8;
const int maxn=25;
int p[maxn];
int c[1<<maxn];
int dp[1<<maxn];
int main(){
int n;
int ccc=0;
while(scanf("%d",&n)!=EOF&&n){
int m,x;
for(int i=0;i<n;i++){
scanf("%d",&m);
p[i]=1<<i;//左移,构造一个只有第i+1位是1的二进制数,为了将0表示在第一位上,故这样操作;
//cout<<p[i]<<endl;
while(m--){
scanf("%d",&x);
p[i]|=(1<<x);//与i直接相连的电脑的表示;
}
}
// for(int i=0;i<n;i++)
// cout<<p[i]<<" ";
// cout<<endl;
c[0]=0;
for(int i=1;i<(1<<n);i++){
c[i]=0;//i表示枚举所有电脑组成的情况;
for(int j=0;j<n;j++)
if(i&(1<<j))
c[i]|=p[j];//若此位上有电脑则将其所有相邻的电脑及本身加入此集合;
}
int all=(1<<n)-1;//只有第n+1位没有电脑,即所有n台都被感染;
for(int i=1;i<(1<<n);i++){
dp[i]=0;
for(int j=i;j;j=(j-1)&i)//子集枚举,减少电脑数与原集合取交集;
if(c[j]==all)/*每台电脑都运行着所有的服务,题意要求每台电脑可以选择关一项服务,
如果c[j]==all表示如果关掉(j在二进制下的表示)的电脑上的某服务,必有一项服务在所有电脑上都被关掉*/;
dp[i]=max(dp[i],dp[i^j]+1);
}
printf("Case %d: %d\n",++ccc,dp[all]);
}
return 0;
}