Miracle Corporations has a number of system services running in a distributed computer system which is a prime target for hackers. The system is basically a set of N computer nodes with each of them running a set of N services. Note that, the set of services running on every node is same everywhere in the network. A hacker can destroy a service by running a specialized exploit for that service in all the nodes. One day, a smart hacker collects necessary exploits for all these N services and launches an attack on the system. He finds a security hole that gives him just enough time to run a single exploit in each computer. These exploits have the characteristic that, its successfully infects the computer where it was originally run and all the neighbor computers of that node. Given a network description, find the maximum number of services that the hacker can damage. Input There will be multiple test cases in the input file. A test case begins with an integer N (1 ≤ N ≤ 16), the number of nodes in the network. The nodes are denoted by 0 to N − 1. Each of the following N lines describes the neighbors of a node. Line i (0 ≤ i < N) represents the description of node i. The description for node i starts with an integer m (Number of neighbors for node i), followed by m integers in the range of 0 to N − 1, each denoting a neighboring node of node i. The end of input will be denoted by a case with N = 0. This case should not be processed. Output For each test case, print a line in the format, ‘Case X: Y ’, where X is the case number & Y is the maximum possible number of services that can be damaged. Sample Input 3 2 1 2 2 0 2 2 0 1 4 1 1 1 0 1 3 1 2 0 Sample Output Case 1: 3 Case 2: 2
学到了新知识:枚举子集 for(int S0 = S; S0 ; S0 = (S0-1) & S ) 但是状态我也没想出来
#include <bits/stdc++.h> using namespace std; const int N = 20; int n, m, Case; int dp[1 << N], p[N], cover[1 << N]; int main() { while(scanf("%d", &n)) { if(!n) break; memset(p ,0 ,sizeof(p)); memset(dp ,0 ,sizeof(dp)); memset(cover ,0 ,sizeof(cover)); for(int i = 0; i < n; ++i) { p[i] = (1 << i); //p[i] 表示i电脑能占领的集合 int m, x; scanf("%d", &m); while(m--) { scanf("%d", &x); p[i] |= (1 << x); } } int All = (1 << n); for(int S = 0; S < All; ++S) for(int i = 0; i < n; ++i) if(S & (1 << i)) cover[S] |= p[i]; //占领S这些电脑能覆盖的集合 for(int i = 0; i < All; ++i) for(int j = i; j ; j = (j - 1) & i) if(cover[j] == All - 1) dp[i] = max(dp[i], dp[i ^ j] + 1); //如果自己的一个子集是全集,那么可以随便选 printf("Case %d: %d ", ++Case, dp[All - 1]); } return 0; }