【UVA11825】Hackers' Crackdown

题面

假设你是一个黑客, 侵入了一个有着n台计算机(编号为0,1,…,n-1) 的网络。 一共有n种服务, 每台计算机都运行着所有服务。 对于每台计算机, 你都可以选择一项服务, 终止这台计算机和所有与它相邻计算机的该项服务(如果其中一些服务已经停止, 则这些服务继续处于停止状态) 。 你的目标是让尽量多的服务器完全瘫痪(即: 没有任何计算机运行该项服务) (1≤n≤16) 

分析

看这样例,真的是状压吗喵喵喵???咋看起来像把联通的环的个数求出来,然后每个环的节点数取min啊...
太蠢了,忽视上面的内心os。以前都是想得太少,这次是想太多了。样例不水还能叫样例吗??计算机之间是可能有传递的影响关系的啊..
我们把每个计算机和它相邻的计算机归入一个集合。
然后将这些集合分组后,使每一组集合并起来都等于全集(即让几组相邻的计算机合起来包含了所有计算机,这样就可以停止一个服务器)
所以用f[s]表示状态为s的最大破坏数量,s的二进制形式第k位的1和0表示第k台服务器有没有被选择
还需要预处理选择每个计算机能覆盖的计算机,用cover[i]存。比如四台计算机中,0和1相邻,1和2相邻,则cover[0]=0111
最后枚举子集,枚举的是选哪些计算机,只要这个子集能覆盖完所有的计算机,就合法。枚举子集的方式:s&(s-1)

代码

#include<bits/stdc++.h>
using namespace std;
#define N 18
int n,x,mx,cnt,cas;
int neb[N],f[1<<N],cover[1<<N];
inline void init()
{
    mx=(1<<n)-1;cas++;
    memset(f,0,sizeof(f));
    memset(neb,0,sizeof(neb));
    memset(cover,0,sizeof(cover));
}
int main()
{
    while(scanf("%d",&n)&&n)
    {
        init();
        for(int i=0;i<n;i++)
        {
            scanf("%d",&cnt);
            neb[i]=1<<i;
            while(cnt--){scanf("%d",&x);neb[i]|=(1<<x);}    
        }
        for(int i=0;i<=mx;i++)
            for(int j=0;j<n;j++)
                if(i&(1<<j))
                    cover[i]|=neb[j];
        for(int s=1;s<=mx;s++)
            for(int s0=s;s0;s0=(s0-1)&s)
                if(cover[s0]==mx)
                    f[s]=max(f[s],f[s^s0]+1);
        printf("Case %d: %d\n",cas,f[mx]);
    }
    return 0;
}

 

 

转载于:https://www.cnblogs.com/NSD-email0820/p/9793214.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值