【状态压缩DP】uva11825Hackers' Crackdown

题目大意:n (n<=20) 台计算机连成网络,每台计算机上都同时运行着N种服务。对于每台计算机,可以选择仅一项服务,终止这台计算机和所有与它相邻计算机的该项服务。求:最多可以让多少种服务完全终止运行。
输入:输入一个n表示有n台计算机。之后的n-1行,表示第i个计算机的连接情况,第一个数字表示有m台计算机与它相连,并给出这些计算机的编号。

本题较难,首先是对题意的理解。即将计算机分为几个联通块,使得每个分组都能实现停止一项服务。
由于n较小,则以计算机的分组为压缩状态。
令f(s)表示以s状态下能停止服务最多,cover[s]表示s联通块。
f(s)=max( f(s) , f(s0) + 1) 其中s0是s的子集,cover[s]为所有计算机。

#include <iostream>
#include <cstdio>
#include <cstring>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;

int n ,node[25] ,f[1<<17] ,cover[1<<17] ,end ,a ,code ;

int main()
{
    while(~scanf("%d",&n)&&n)
    {
        memset(cover,0,sizeof(cover));
        for(int i=0;i<n;++i)
        {
            node[i]=1<<i;
            scanf("%d",&a);
            for(int i=0;i<a;++i)
            {
                scanf("%d",&a);
                node[i] |= 1<<a;
            }
        }
        end=(1<<n)-1;
        //预处理cover数组 cover[s]表示在s的情况下 s中的计算机所组成的联通块
        for(int s=0;s<=end;++s)
            for(int i=0;i<n;++i)
                if(s & (1<<i))
                    cover[s] |= node[i];
        for(int s=0;s<=end;++s)
        {
            f[s]=0;
            for(int s0=s;s0;s0=(s0-1)&s)//求s的子集
                if(cover[s0]==end)
                    f[s]=max(f[s],f[s0]+1);
        }
        printf("Case %d: %d\n",++code,f[end]);
    }
    return 0;
}

你可能感兴趣的:(状压dp,uva11825)