题意:有n台计算机的网络,每台计算机上都运行着n种服务,对于每台计算机你都可以选择一项服务,终止这台计算机上的和所有和它相邻的计算机的该项服务你的目标是让尽量多的服务完全瘫痪,(即:没有任何一台计算机运行该项服务)
思路:把每台计算机和其相邻的计算机放入集合p[i]中,把n个集合p[i]分成尽量多的且两两没有交集的分组,使得每个分组的所有集合的并集等于全集。
那么最后我们可以利用每一个分组来停止一项服务。
状态:dp[s]表示s最后可以分出的组数。
状态转移:dp[s] = max(dp[s0] | so是s的子集,且cover[s0]等于全集)+1。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 16 int n, m, x, dp[1<<N], cover[1<<N], p[N]; int main () { int k = 0; while(scanf("%d",&n), n) { for(int i = 0; i < n; i++) { p[i] = 1<<i; scanf("%d",&m); for(int j = 0; j < m; j++) { scanf("%d",&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]; } dp[0] = 0; int all = (1<<n)-1; for(int s = 1; s < (1<<n); s++) { dp[s] = 0; for(int s0 = s; s0; s0 = (s0-1)&s) if(cover[s0]==all) dp[s] = max(dp[s], dp[s^s0]+1); } printf("Case %d: %d\n",++k, dp[all]); } return 0; }