uva11825

参考: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;
}

猜你喜欢

转载自blog.csdn.net/chenyume/article/details/82810198
今日推荐