• UVA11825 黑客的攻击 Hackers' Crackdown 状压DP,二进制,子集枚举


    题目链接Click Here

    【题目描述】

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

    【输入格式】

    输入包含多组数据,每组数据的第一行为整数(n(1<=n<=16)):以下(n)行每行描述一台计算机相邻的计算机,其中第一个数(m)为相邻计算机个数,接下来的(m)个整数为这些计算机的编号。输入结束标志(n=0)

    【输出格式】

    对于每组数据,输出完全瘫痪的服务的数量。


    本题实际上可以转化为:给你(n)个集合(p_{1 -> n}),你要把它们分成尽可能多的组,每个组内所有集合的并等于全集。

    因为(n)比较小,所以我们可以把每个集合(P)(每个点自身(+)它相邻的点)二进制状压。考虑选取一些集合时,把选取的集合也二进制状压(表示为(S)),存一下该选取状态下可以覆盖的状况即可((cover_s))。

    这样我们可以得到方程:

    [f(S) = max (f(S - S_0)|S_0∈S, cover_{S_0} = S_{All}) ]

    技巧:二进制下的子集枚举:

    for (int S0 = S; S0 != 0; S0 = (S0 - 1) & S) 
    

    这样为什么能实现子集枚举呢?请读者自行思考(笑

    复杂度:(O(sum_{k=1->N}C(n, k) * 2 ^ n) = O(3 ^ n))。为什么等于后面我不会二项式定理所以不大会。

    关注点:本题中的子集枚举思想。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 20;
    
    int Case, n, m, to, s[N], f[N], cho[1 << N];
    
    int main () {
    //	freopen ("data.in", "r", stdin);
    	while (cin >> n && n) {
    		for (int i = 0; i < n; ++i) {
    			cin >> m; s[i] = 1 << i;
    			for (int j = 0; j < m; ++j) {
    				cin >> to; s[i] |= 1 << to;
    			} 	
    //			cout << "s[" << i << "] = " << s[i] << endl;
    		} 
    		const int All = (1 << n) - 1;
    		for (int i = 0; i < 1 << n; ++i) {
    			cho[i] = 0;
    			for (int k = 0; k < n; ++k) {
    				if ((i >> k) & 1) {
    					cho[i] |= s[k];
    				}
    			}
    		}
    		f[0] = 0;
    		for (int S = 1; S < (1 << n); ++S) {
    			f[S] = 0;
    			for (int S0 = S; S0; S0 = (S0 - 1) & S) { //枚举S的子集 
    				if (cho[S0] == All) {
    					f[S] = max (f[S], f[S ^ S0] + 1);
    				}
    			}
    		}
    		cout << "Case " << ++Case << ": " << f[All] << endl;
    	}
    }
    
  • 相关阅读:
    oracle中查询或插入特殊字符
    html最多显示两行,css 实现两行或多行文本溢出显示省略号(...)
    RT
    发表一个自己做的WPF游戏
    用silverlight制作自己的GIS
    一个字符串切割问题
    Oracle所有者权限与调用者权限(转)
    Oracle角色权限的使用事项(转)
    Tomcat 内存溢出 详解
    forms验证:怎么验证两种身份?
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10688004.html
Copyright © 2020-2023  润新知