UVA 11825Hackers' Crackdown dp+位运算状态压缩(子集枚举)

来源:互联网 发布:淘宝上的订单险是什么 编辑:程序博客网 时间:2024/06/05 22:35

题意:

      有N台电脑(编号为0,1,2......n-1),每台电脑有N(N<=16)个服务,一个黑客可以在每台电脑上种植让其中一种服务崩溃的病毒,并且这个病毒可以传播到跟他邻接的电脑,问最多这个黑客可以让多少个服务崩溃?(每台电脑上都是N个不同服务,每台电脑上跑的都是一样的服务,让一个服务崩溃是让所有的电脑上的这个服务崩溃)

Input

There will be multiple test cases in the input file. A test case begins with an integer N (1 ≤ N ≤ 16),the number of nodes in the network. The nodes are denoted by 0 to N − 1. Each of the followingN lines describes the neighbors of a node. Line i (0 ≤ i < N) represents the description of node i.The description for node i starts with an integer m (Number of neighbors for node i), followed by mintegers in the range of 0 to N − 1, each denoting a neighboring node of node i.

The end of input will be denoted by a case with N = 0. This case should not be processed.

Output

For each test case, print a line in the format, ‘Case X: Y ’, where X is the case number & Y is themaximum possible number of services that can be damaged.

Sample Input

3

2 1 2

2 0 2

2 0 1

4

1 1

1 0

1 3

1 2

0

Sample Output

Case 1: 3

Case 2: 2

 分析:

本题的数学模型:

把n个集合p1,p2,p3...pn分成尽量多组,并且使得每一组集合的并集等于全集S。

f[s]表示集合至多能分成几组,

注意到n<=16,于是每台电脑与其他电脑的关系,也就是前面说的p1,p2...pn,可以用一个二进制数来表示:

相邻的为1,不相邻的为0,全集全为1;

方程:

f(s)= max{f(s-S0) | S0是s的子集,并且crash[S0]==全集S}+1;

其中,crach[S]表示集合S关系到的所有的p[i]的并集(用位运算的'|‘来表达)

时间的复杂度等于{1,2,3......n}的所有子集的子集的个数。总之用很牛逼的方法可以知道,它是O(3^n)。

代码如下:

#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int maxn=16;int n,f[(1<<maxn)+5],crash[(1<<maxn)+5],p[maxn];void input(){int i,s,m,x;scanf("%d",&n);for(i=0;i<n;i++){scanf("%d",&m);p[i]= 1<<i; //最初只有自己 while(m--){scanf("%d",&x);p[i]|=(1<<x);  }}memset(crash,0,sizeof(crash));for(s=0;s<(1<<n);s++){  //预处理crash[s]; crash[s]=0;for(i=0;i<n;i++)if(s&(1<<i))crash[s]|=p[i];  //并集操作 } }void solve(int kase){int all= (1<<n)-1,s,s0;for(s=1;s<(1<<n);s++){f[s]=0;  //多组数据。不要忘了初值 for(s0=s;s0;s0=(s0-1)&s)  //枚举s的子集s0; if(crash[s0]==all)f[s]=max(f[s],f[s-s0]+1); //也可写成f[s^s0]+1; }printf("Case %d: %d\n",kase,f[all]);}int main(){for(int i=1;;i++){input();if(n==0)return 0;solve(i);}}/* 枚举子集的模型:对于集合s:for(s0=s;s0;s0=(s0-1)&s)*/ 


0 0
原创粉丝点击