Uva 11825 Hackers' Crackdown ACM解题报告(状压dp)

这题的题意是有n个电脑,每个电脑都有n个服务,然后每台电脑都和某几台电脑相邻,有个黑客可以在每台电脑上停止一个服务,然后这台电脑和与它相邻的电脑上的这个服务都会停止,问最多可以停止多少个服务。

这题就是要把电脑之间的关系化成集合,因为n的范围比较小,所以可以状态压缩,用(1<<n)-1表示电脑的全集,然后每台电脑及和它相邻的电脑可以用p[i]用二进制记录,然后就是开个cover数组,下标取全集的子集,看子集里的这些电脑加上它们相邻的电脑,意思是在选中的这些电脑上停止某个服务,加上它们相邻影响到的电脑,能否覆盖整个集合(n台电脑)。

状态转移时f[s]=max(f[s-s0])+1,s0是s的子集,cover[s0]=全集。

#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<stack>
using namespace std;
#define MAX 105
typedef long long LL;
const double pi=3.141592653589793;
const int INF=1e9;
const double inf=1e20;
const double eps=1e-6;
int cover[70000],f[70000];
int main(){
	int n,m,x,kase=0;
	int p[20];
	while(cin>>n&&n){
		kase++;
		for(int i=0;i<n;i++){
			cin>>m;
			p[i]=(1<<i);
			while(m--){
				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=0;s<=all;s++){
			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;
}


你可能感兴趣的:(动态规划,ACM,uva)