• 【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
    ",cas,f[mx]);
        }
        return 0;
    }

     

    “Make my parents proud,and impress the girl I like.”
  • 相关阅读:
    Django之Orm的各种操作
    python面试题---收藏的笔记
    jQuery中$.each()方法的使用
    Django 之 路由URL,视图,模板
    高级FTP服务器开发
    选课系统
    ATM
    开发一个简单的python计算器
    学习PYTHON之路, DAY 8
    学习PYTHON之路, DAY 7
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9793214.html
Copyright © 2020-2023  润新知