uva 11825 黑客的攻击 Hackers' Crackdown 集合dp+我的优化 非常好的好题
2016-02-05 16:25
309 查看
题目:点我
题目大意:(黑客的攻击)假设你是一个黑客,侵入了了一个有着n台计算机(编号为0,1,…,n-1)的网络。一共有n种服务,每台计算机都运行着所有的服务。对于每台计算机,你都可以选择一项服务,终止这台计算机和所有与它相邻计算机的该项服务(如果其中一些服务已经停止,则这些服务继续处于停止状态)。你的目标是让尽量多的服务器完全瘫痪(即:没有任何计算机运行该项服务)
输入格式:输入包含多组数据。每组数据的第一行为整数n(1<=n<=16);以下n行每行描述一台计算机的相邻计算机,其中第一个数m为相邻计算机个数,接下来的m个整数位这些计算机的编号。输入结束标志为n=0。
输出格式:对于每组数据,输出完全瘫痪的服务器的最大数量。
几天以前看这个题目,觉得特别难,因为n很小,n<=16,所以很容易想到集合dp,可是就算想到了,当时也觉得非常难表示,因为觉得既要表示各种服务是否工作的集合,又要表示每台计算机切断哪种服务的集合。觉得非常难。
假设不用集合dp,那就更难,不仅是更难,简直是灾难,状态都无法表示。
我最近想问题,总是老想些过于复杂的部分,导致很多问题都无法思考出结果,比如这个题目,我总想着一个计算机选择一种服务后,有16种选择,还要遍历与他相邻的计算机,用动态规划去解决一个有复杂结构的图问题,怎么样想这个题能够解决都是令人无法相信的。
我发现决策最多只有n种,所以弄出了n个泛化物品(n个选择用n个物品表示),每个物品是一个集合,表示哪些计算机与选中的计算机相领,
然后把选中的计算机也加进去。
然后去枚举,哪些选中的组合能够完全停止一种服务。我们不必关心是哪一种,我们只关心是否能完全停止一种。
怎么去枚举?有事用int表示集合!表示选中了哪些为中心计算机。
最后开始状态转移,从0开始到(1<<n)-1 ,dp[x]表示状态x(切断了某些为中心的计算机后)能够完全停止的最多服务。
最后你会发现这样做会超时,因为泛化物品(指的是组合,能够完全停止一种服务的组合)实在数目太多了,后来想了个办法,把没用的物品(如果没有,也不影响最优解)都给他去了,时间省了不少。(newS()函数)
这个题目确实觉得挺好,对于我这种小白,做这一题的过程简直是一波三折,做完令人回味无穷。
如果对于状态S,枚举S的子集进行动态规划(与我的不同)是不会超时的,时间复杂度O(3^n);
题目大意:(黑客的攻击)假设你是一个黑客,侵入了了一个有着n台计算机(编号为0,1,…,n-1)的网络。一共有n种服务,每台计算机都运行着所有的服务。对于每台计算机,你都可以选择一项服务,终止这台计算机和所有与它相邻计算机的该项服务(如果其中一些服务已经停止,则这些服务继续处于停止状态)。你的目标是让尽量多的服务器完全瘫痪(即:没有任何计算机运行该项服务)
输入格式:输入包含多组数据。每组数据的第一行为整数n(1<=n<=16);以下n行每行描述一台计算机的相邻计算机,其中第一个数m为相邻计算机个数,接下来的m个整数位这些计算机的编号。输入结束标志为n=0。
输出格式:对于每组数据,输出完全瘫痪的服务器的最大数量。
几天以前看这个题目,觉得特别难,因为n很小,n<=16,所以很容易想到集合dp,可是就算想到了,当时也觉得非常难表示,因为觉得既要表示各种服务是否工作的集合,又要表示每台计算机切断哪种服务的集合。觉得非常难。
假设不用集合dp,那就更难,不仅是更难,简直是灾难,状态都无法表示。
我最近想问题,总是老想些过于复杂的部分,导致很多问题都无法思考出结果,比如这个题目,我总想着一个计算机选择一种服务后,有16种选择,还要遍历与他相邻的计算机,用动态规划去解决一个有复杂结构的图问题,怎么样想这个题能够解决都是令人无法相信的。
我发现决策最多只有n种,所以弄出了n个泛化物品(n个选择用n个物品表示),每个物品是一个集合,表示哪些计算机与选中的计算机相领,
然后把选中的计算机也加进去。
然后去枚举,哪些选中的组合能够完全停止一种服务。我们不必关心是哪一种,我们只关心是否能完全停止一种。
怎么去枚举?有事用int表示集合!表示选中了哪些为中心计算机。
最后开始状态转移,从0开始到(1<<n)-1 ,dp[x]表示状态x(切断了某些为中心的计算机后)能够完全停止的最多服务。
最后你会发现这样做会超时,因为泛化物品(指的是组合,能够完全停止一种服务的组合)实在数目太多了,后来想了个办法,把没用的物品(如果没有,也不影响最优解)都给他去了,时间省了不少。(newS()函数)
/**========================================== * This is a solution for ACM/ICPC problem * * @source:uva 11825 Hackers' Crackdown * @type: dp * @author: wust_ysk * @blog: http://blog.csdn.net/yskyskyer123 * @email: 2530094312@qq.com *===========================================*/ #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> #include<vector> #define ysk(x) (1<<(x)) using namespace std; typedef long long ll; const int INF =0x3f3f3f3f; vector<int>things; int n,m,ed; int a[18]; int dp[ysk(16)+5]; bool vis[ysk(16)+5]; bool newS(int s) { for(int i=0;i<n;i++) if(s&ysk(i)) { int nst=s^ysk(i); if(vis[nst]) return false; } return true; } void virtual_things() { things.clear(); memset(vis,0,sizeof vis); for(int s=1;s<=ed;s++) { int tot=0; for(int j=0;j<n;j++) if(s&ysk(j)) { tot|=a[j]; } if(tot==ed) { if(newS(s)) things.push_back(s); vis[s]=1; } } } int main() { int x,kase=0; while(~scanf("%d",&n)&&n) { for(int i=0;i<n;i++) { int st=ysk(i); scanf("%d",&m); for(int j=0;j<m;j++) { scanf("%d",&x); st|=ysk(x); } a[i]=st; } ed=ysk(n)-1; virtual_things(); memset(dp,0, (ed+1)*sizeof dp[0]); for(int st=0;st<ed;st++) { for(int i=0;i<things.size();i++) { int add=things[i]; if(st&add) continue; int nex=st|add; dp[nex]=max(dp[nex],dp[st]+1); } } printf("Case %d: %d\n",++kase,dp[ed]); } return 0; } /* 3 2 1 2 2 0 2 2 0 1 4 1 1 1 0 1 3 1 2 */
这个题目确实觉得挺好,对于我这种小白,做这一题的过程简直是一波三折,做完令人回味无穷。
如果对于状态S,枚举S的子集进行动态规划(与我的不同)是不会超时的,时间复杂度O(3^n);
相关文章推荐
- 安卓手机用WIFI与电脑共享文件
- Qt 实例--计算圆面积
- nyoj283对称排序
- 微信公众平台开发接口PHP SDK完整版
- c#编程之UDP通信
- USACO 3.1.1
- Android项目中引用外部项目library失败的原因
- iOS开发的一些奇巧淫技 包括一款GIF框架
- Xcode project文件
- android 入门 004 (同一个方法,点击实现不同的效果)
- Silverlight+wcf程序
- 零点计费系统_Ros云计费(下面是对接教程)
- mysql性能查看和配置整理大全
- C++数据结构栈的实现
- flex调用webservice绑定DataGrid
- Android Activity生命周期整理
- QT【绘图】 QPaintDevice 总结:QPixmap、QImage、QBitmap和QPicture
- flash的google地图
- KVM虚拟化笔记(十)------kvm虚拟机扩充磁盘空间
- USACO 1.2 milk2