【动态规划】[UVa 11825]Hackers' Crackdown

来源:互联网 发布:最优化方法孙文瑜答案 编辑:程序博客网 时间:2024/05/22 12:14

这道题目用DP来搞首先题目可以看成把所有的计算机分成很多组每一组的都关闭同一种服务,同时这一组的关闭能够关闭所有的计算机,那么另S为当前的所有计算机的集合另S0S的子集另全集(所有计算机)为S那么可以很容易的发现f(S)=max{f(S0)+(S==cover(S0))}其中cover(S0)表示的是S0所能够覆盖的集合,这道题还有唯一的要注意的就是在读入的时候处理每一个计算机能够覆盖的集合的时候不要忘了吧自己给加进去

#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int MAXN = 16;int P[MAXN+10], cover[(1<<MAXN)+1], n, m;void GetaCover(int S){    int tmp = S, t=0;    cover[S] = 0;    while(S){        if(S & 1)            cover[tmp] |= P[t];        S >>= 1;        t++;    }}bool Read(){    int t;    scanf("%d", &n);    if(n == 0) return false;    for(int i=0;i<n;i++){        scanf("%d", &m);        P[i] = 1 << i;        for(int j=0;j<m;j++){            scanf("%d", &t);            P[i] |= (1 << t);        }    }    t = 1 << n;    for(int i=0;i<t;i++)        GetaCover(i);    return true;}int f[(1<<MAXN)+2];int solve(){    int Max = 1 << n;    for(int S=0; S<Max; S++){        f[S] = 0;        for(int S0=S; S0; S0=(S0-1)&S)            f[S] = max(f[S], f[S-S0]+int(cover[S0]==(Max-1)));    }    return f[Max-1];}int main(){    int cas = 0;    while(Read()){        printf("Case %d: %d\n", ++cas, solve());    }    return 0;}
0 0