传送门

Description

  你是一个hacker,侵入了一个有着n台计算机(编号为1.2.3....n)的网络。一共有n种服务,每台计算机都运行着所有服务。对于每台计算机,你都可以选择一项服务,终止这台计算机和所有与它相邻计算机的该项服务(如果其中一些服务已经停止,那他们继续保持停止状态)。你的目标是让尽量多的服务完全瘫痪

Input

输入包含多组数据,每组数据中:

  • 第一行为整数n:
  • 以下n行每行描述一台计算机相邻的计算机,
  • 其中第一个数m为相邻计算机个数,接下来的m个整数为这些计算机的编号。

输入结束标志n=0

Output

对于每组数据:

  • 输出完全瘫痪的服务的数量

格式见样例

Sample Input

  1.  

Sample Output

  1. Case :
  2. Case :

Hint

1<=n<=16

Solution

  考虑对于每种服务,显然需要所有计算机都停掉才有价值。

  我们设Seti为i和i相邻的计算机编号的集合。由于数据范围小,显然所有的集合都可以二进制表示,以下不再赘述。

  那么本题所求就变为将所有的Set最多分为几组,使得每组的Set的并集都为全集。

  我们设fi为只考虑集合i中元素的ans。

  转移显然:

  f[i]=max{f[i^j]|集合j的set并集为全集且j是i的子集}+1

  考虑阶段:

  最简单的方法当然是按照元素个数枚举,但是在本题中难以操作。

  考虑以下事实 :

  设i从j转移过来,那么j为i的子集。在二进制表示下,显然有j≤i。那么按照i升序枚举,显然j在计算i时已经被计算完毕。

  现在考虑如何高效率枚举i的子集:

  朴素的枚举方式如下:

  1. int ziji=;
  2. for(int i=;i<n;++i)
  3. if((<<i)&s) ziji|=(<<i)

  考虑优化效率:

  1. for(rg int i=;i<=upceil;++i) {
  2. for(rg int j=i;j;j=(j-)&i) {
  3. dosth();
  4. }
  5. }

  内层循环可以高效枚举i的子集,其时间效率为O(|i|),其中|i|代表i在二进制意义下表示的集合的元素个数.

  继续考虑优化:

  在枚举子集后,如果可以快速判断该集合中元素对应的set的并集是否为全集可以大大提高时间效率,这样我们令S0[i]为i在二进制意义下所代表的集合的元素对应的set的并集的二进制(这是什么鬼畜句型。我们可以通过预处理做到O(1)查询并集。

  预处理时,枚举每个集合,暴力枚举每个元素j是否属于该集合,如果是,则S0[i]|=Set[j]。时间复杂度O(n*2n)。

  这样思路就完成了:

  预处理出计算机i的子集Set,通过枚举选择的计算机编号,进行DP转移。

  事实上,这是一个状压套状压的题目。我们枚举的是计算机的编号,而判断的是编号所对应的Set的集合的并集是否等于全集。

  考虑时间复杂度:

  参照循环,时间复杂度为全集的子集的子集个数和。

  由于元素个数为x的元素子集有C(n,x)个,每个子集有2x个子集,所以元素个数为Σ(x:1 to n)C(n,x)*2x。由二项式定理得,原式=(2+1)n=3n

  所以程序得时间复杂度为θ(3n+n*2n)=O(3n)

Code

  1. #include<cstdio>
  2. #include<cstring>
  3. #define rg register
  4. #define ci const int
  5.  
  6. inline void qr(int &x) {
  7. char ch=getchar(),lst=NULL;
  8. while(ch>''||ch<'') lst=ch,ch=getchar();
  9. while(ch>=''&&ch<='') x=(x<<)+(x<<)+(ch^),ch=getchar();
  10. if (lst=='-') x=-x;
  11. }
  12.  
  13. char buf[];
  14. inline void write(int x,const char aft,const bool pt) {
  15. if(x<) {putchar('-');x=-x;}
  16. int top=;
  17. do {
  18. buf[++top]=x%+'';
  19. x/=;
  20. } while(x);
  21. while(top) putchar(buf[top--]);
  22. if(pt) putchar(aft);
  23. }
  24.  
  25. template <typename T>
  26. inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
  27. template <typename T>
  28. inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
  29. template <typename T>
  30. inline T mabs(const T &a) {if(a<) return -a;return a;}
  31.  
  32. template <typename T>
  33. inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;}
  34.  
  35. const int maxn = ;
  36. const int maxt = ;
  37. const int maxm = ;
  38.  
  39. int n,a,b,cnt,ans;
  40.  
  41. int frog[maxt];
  42. int Set[maxn];
  43. int s0[maxt];
  44.  
  45. void clear();
  46.  
  47. int main() {
  48. qr(n);
  49. while(n) {
  50. clear();
  51. for(rg int i=;i<n;++i) {
  52. a=;qr(a);
  53. while(a--) {
  54. b=;qr(b);
  55. Set[i]|=(<<b);
  56. }
  57. Set[i]|=(<<i);
  58. }
  59. rg const int upceil=(<<n)-;
  60. for(rg int i=;i<=upceil;++i) {
  61. for(rg int j=;j<n;++j) {
  62. int k=<<j;
  63. if(k>i) break;
  64. if(i&k) s0[i]|=Set[j];
  65. }
  66. }
  67. for(rg int i=;i<=upceil;++i) {
  68. for(rg int j=i;j;j=(j-)&i) {
  69. if(s0[j]==upceil) {frog[i]=mmax(frog[i],frog[j^i]+);}
  70. }
  71. ans=mmax(frog[i],ans);
  72. }
  73. printf("Case %d: %d\n",++cnt,ans);
  74. n=;qr(n);
  75. }
  76. return ;
  77. }
  78.  
  79. void clear() {
  80. memset(s0,,sizeof s0);
  81. memset(Set,,sizeof Set);
  82. memset(frog,,sizeof frog);
  83. ans=;
  84. }

Summary

1、子集枚举方式需要牢记。

2、在一些由子集转移来得题目中,可以将集合序号作为阶段。

3、计算复杂的得时候二项式定理会被经常使用

4、在高复杂度问题中,预处理是个好东西。

【状压DP】【UVA11825】 Hackers' Crackdown的更多相关文章

  1. UVa 11825 (状压DP) Hackers' Crackdown

    这是我做状压DP的第一道题,状压里面都是用位运算来完成的,只要耐下心来弄明白每次位运算的含义,还是容易理解的. 题意: 有编号为0~n-1的n台服务器,每台都运行着n中服务,每台服务器还和若干台其他服 ...

  2. UVa 11825 Hackers' Crackdown (状压DP)

    题意:给定 n 个计算机的一个关系图,你可以停止每台计算机的一项服务,并且和该计算机相邻的计算机也会终止,问你最多能终止多少服务. 析:这个题意思就是说把 n 台计算机尽可能多的分成一些组,使得每组的 ...

  3. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

  4. nefu1109 游戏争霸赛(状压dp)

    题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...

  5. poj3311 TSP经典状压dp(Traveling Saleman Problem)

    题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...

  6. [NOIP2016]愤怒的小鸟 D2 T3 状压DP

    [NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...

  7. 【BZOJ2073】[POI2004]PRZ 状压DP

    [BZOJ2073][POI2004]PRZ Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍 ...

  8. bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)

    数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...

  9. HDU 1074 Doing Homework (状压dp)

    题意:给你N(<=15)个作业,每个作业有最晚提交时间与需要做的时间,每次只能做一个作业,每个作业超出最晚提交时间一天扣一分 求出扣的最小分数,并输出做作业的顺序.如果有多个最小分数一样的话,则 ...

  10. 【BZOJ1688】[Usaco2005 Open]Disease Manangement 疾病管理 状压DP

    [BZOJ1688][Usaco2005 Open]Disease Manangement 疾病管理 Description Alas! A set of D (1 <= D <= 15) ...

随机推荐

  1. 统计hive库表在具体下所有分区大小

    1 查询具体表分区大小,以字节展示 hadoop fs -du /user/hive/warehouse/treasury.db/dm_user_excercise > dm_user_exce ...

  2. org.apache.spark.sql.functions汇总

    测试数据: id,name,age,comment,date 1,lyy,28,"aaa bbb",20180102020325 scala> var data = spar ...

  3. AngularJS 初探

    AngularJS,诞生于2009年,由Misko Hevery等人创建,后为Google所收购.这是一款优秀的前端JS框架,已经被用于Google的多款产品当中.AngularJS有着诸多特性,最为 ...

  4. Ubuntu 16.04 安装显卡驱动后循环登录和无法设置分辨率的一种解决方案

    1. 安装环境 电脑:MSI GP63 显卡:GeForce GTX 1070 系统:Ubuntu 16.04 驱动版本:NVIDIA 384.130 2. 循环登录 如果按照这篇文章 Ubuntu ...

  5. springMVC对jsp页面的数据进行校验

    一. 使用注解校验 a) 引入校验依赖包 <dependency> <groupId>javax.validation</groupId> <artifact ...

  6. Ext JS 6学习文档-第4章-数据包

    Ext JS 6学习文档-第4章-数据包 数据包 本章探索 Ext JS 中处理数据可用的工具以及服务器和客户端之间的通信.在本章结束时将写一个调用 RESTful 服务的例子.下面是本章的内容: 模 ...

  7. ViewPager的简单使用说明

    前提:工程中使用ViewPager,需要导入google提供的jar包(android-support-v4.jar). 要学习ViewPager的使用,建议直接看官方文档 Creating Swip ...

  8. NProgress.js加载进度插件的简单实用方法

    NProgress.js 说明: NProgress是基于jquery的,且版本要 >1.8 下载地址: https://github.com/rstacruz/nprogress API: N ...

  9. Web后台任务处理

    文章:.NET Core开源组件:后台任务利器之Hangfire Hangfire官网介绍:在.NET和.NET Core应用程序中执行后台处理的简便方法.无需Windows服务或单独的过程. 以持久 ...

  10. lintcode-178-图是否是树

    178-图是否是树 给出 n 个节点,标号分别从 0 到 n - 1 并且给出一个 无向 边的列表 (给出每条边的两个顶点), 写一个函数去判断这张`无向`图是否是一棵树 注意事项 你可以假设我们不会 ...