UVA 11825 Hackers' Crackdown 状态DP
题意:
有一个由编号0~n-1的n台计算机组成的网络,一共有n种服务,每台计算机上都运行着全部服务,对于每台计算机,你可以选择停止一项服务,这个行为会导致与这台计算机和与他相连的其他计算机上的这项服务都停止(原来已经停止的继续保持停止状态)。求最多能使多少个服务瘫痪(即没有任何一台计算机在运行这项服务)。
首先是一个枚举子集的技巧
for(int sub=S;sub>0;sub=(sub-1)&S)
问题抽象成数学模型就是:
把n个集合p[i],0<=i<n分成尽量多组,使得每组中各个集合的并集为全集
p[i]就是表示与i相连的计算机集合(包括i)
int n; int p[16]; int read() { for(int i=0;i<n;i++) { p[i]=(1<<i); int m; scanf("%d",&m); for(int j=0;j<m;j++) { int x; scanf("%d",&x); p[i]|=(1<<x); } } return 0; } int c[1<<16]; int dp[1<<16]; int main() { int ca=1; while(scanf("%d",&n)!=EOF&&n) { read(); int total=(1<<n)-1; for(int st=0;st<=total;st++) { c[st]=0; for(int i=0;i<n;i++) { if(st&(1<<i))c[st]|=p[i]; } } memset(dp,0,sizeof(dp)); for(int st=0;st<=total;st++) { for(int sub=st;sub>0;sub=(sub-1)&st)if(c[sub]==total) { dp[st]=max(dp[st],dp[st^sub]+1); } } printf("Case %d: %d\n",ca++,dp[total]); } return 0; }