黑客的攻击 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]); } }