uva 11825

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\n", ++Case, dp[All - 1]);
    }
    return 0;
}

 

posted @ 2017-03-14 23:39  19992147  阅读(154)  评论(0编辑  收藏  举报