题意: 假设你是一个黑客,入侵了一个有着n台计算机的网络(0,1,...n-1),一共有n种服务
每台计算机都运行着所有的业务,对于每台计算机,你都可以选择一项服务,终止这台计算机和所有与它相连的计算机的该业务,你的目标是让尽量多的服务完全瘫痪(没有计算机运行该业务),输出完全瘫痪的服务的最大数量
思路:本题的数学模型是:将n个集合P1,P2,...Pn分成尽量多组,使的每组中所有集合的并集等于全集,这里的集合Pi是计算机i及其相邻的计算机的集合,每组对应于题目中的一项服务,分的组越多那么就代表能破坏的服务越多
用cover(S)表示若干Pi的集合S中所有Pi的并集,状态转移方程是:
f(s) = max(f(S-S0)|S0是S的子集,cover[S0] = 全集) + 1
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 1<<17+10; int p[MAXN],cover[MAXN],dp[MAXN]; int n; int main(){ int cas = 1; while (scanf("%d",&n) != EOF && n){ for (int i = 0; i < n; i++){ p[i] = 1<<i; int m; scanf("%d",&m); while (m--){ int x; scanf("%d",&x); p[i] |= (1<<x); } } for (int i = 0; i < (1<<n); i++){ cover[i] = 0; for (int j = 0; j < n; j++) if (i & (1<<j)) cover[i] |= p[j]; } dp[0] = 0; int full = (1<<n) - 1; for (int i = 1; i <= full; i++){ dp[i] = 0; for (int j = i; j; j = (j-1)&i) if (cover[j] == full) dp[i] = max(dp[i],dp[i^j]+1); } printf("Case %d: %d\n",cas++,dp[full]); } return 0; }