黑客的攻击 Hacker‘s crackdown UVA11825 状态压缩动态规划

题目的意思是有n台服务器运行着n类程序,一个黑客有n中类的病毒,最多每台服务器可以放一种病毒,但是相邻的服务器会感染同种病毒,只暂停一种服务,问能够暂停的程序的最大种数。

解决的方法是,用位表示集合,问题的答案相当于是求出最多集合的组合,组合内的集合并集是全集。求这些组合最大的数目。转移方程式f[s]={f[s^s0],s0这种组合内的集合并集是全集}+1.

这里涉及到一些集合的操作:

或运算,将元素加入到集合之中。

枚举集合的所有组合的可能性:

for(int i=0;i<(1<<n);i++)
{
    for(int j=0;j<n;j++)
   {
        if(i&(1<<n))cover[i]=cover[i]|s[j];
    }
}

枚举集合s的所有子集

for(int i=s;i>0;i=(i-1)&s)
{
    //insert code
}

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 1<<17
int cover[MAXN];
int s[20];
int f[MAXN];
int main()
{
	int n;
	int kas=0;
	while(scanf("%d",&n),n)
	{
		memset(s,0,sizeof(s));
		for(int i=0;i<n;i++)
		{
			int m;cin>>m;
			s[i]=s[i]|(1<<i);
			for(int j=0;j<m;j++)
			{
				int t;cin>>t;
				s[i]=s[i]|(1<<t);
			}
		}
		memset(cover,0,sizeof(cover));
		for(int i=0;i<(1<<n);i++)
		{
                       for(int j=0;j<n;j++)
		       {
			       if(i&(1<<j))cover[i]=cover[i]|s[j];
		       }
		}
		memset(f,0,sizeof(f));
		for(int i=0;i<(1<<n);i++)
		{
			for(int j=i;j>0;j=(j-1)&i)
			{
				if(cover[j]==(1<<n)-1)
				{
					f[i]=max(f[i],f[i^j]+1);
				}
			}
		}
		printf("Case %d: %d\n",++kas,f[(1<<n)-1]);
	}
}


 

 

 

 

 

 

 

 

你可能感兴趣的:(rack)