UVa 11825 - Hackers' Crackdown DP, 枚举子集substa = (substa - 1)&sta 难度: 2

题目

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2925

题意

n个节点,每个节点都有完全相同的n项服务。

每次可以选择一个节点,破坏该节点和相邻节点的某项服务。

问最多能完全破坏多少服务?

思路

如刘书,

直接枚举状态的子集

注意元素个数为k的集合有C^k_n个子集,那么枚举的时间复杂度为sum{c^k_n * 2^k} = 3^n,当n=16时,3^n=4e7,可以承受。

注意枚举子集可以通过substa = (substa - 1)&sta来做,子集的补集则为substa ^ sta。

感想

1. 一开始觉得枚举时间是2^2n,觉得不行,还是缺乏细致的计算

代码

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <tuple>
#define LOCAL_DEBUG
using namespace std;
typedef pair<int, int> MyPair;
const int MAXN = 16;
const int MAXSTA = 1 << 16;
int edges[MAXN][MAXN];
int edgeCnt[MAXN];
int vis[MAXN];
int vis2[MAXSTA];
int dp[MAXSTA];

int main() {
#ifdef LOCAL_DEBUG
    freopen("C:\\Users\\Iris\\source\\repos\\ACM\\ACM\\input.txt", "r", stdin);
    //freopen("C:\\Users\\Iris\\source\\repos\\ACM\\ACM\\output.txt", "w", stdout);
#endif // LOCAL_DEBUG
    int n;
    for (int ti = 1; scanf("%d", &n) == 1 && n; ti++) {
        for (int i = 0; i < n; i++) {
            scanf("%d", edgeCnt + i);
            for (int j = 0; j < edgeCnt[i]; j++) {
                scanf("%d", edges[i] + j);
            }
        }
        int maxsta = (1 << n) - 1;
        for (int sta = 0; sta <= maxsta; sta++) {
            memset(vis, 0, sizeof vis);
            for (int i = 0; i < n; i++) {
                if (sta & (1 << i)) {
                    vis[i] = true;
                    for (int j = 0; j < edgeCnt[i]; j++) {
                        vis[edges[i][j]] = true;
                    }
                }
            }
            bool fl = true;
            for (int i = 0; i < n; i++) {
                if (!vis[i]) {
                    fl = false;
                }
            }
            if (fl) {
                dp[sta] = 1;
            }
            else {
                dp[sta] = 0;
            }

        }
        for (int sta = 0; sta <= maxsta; sta++) {
            for (int subSta = sta; subSta != 0; subSta = (subSta - 1) & sta) {
                dp[sta] = max(dp[sta], dp[sta ^ subSta] + dp[subSta]);
            }

        }
        printf("Case %d: %d\n", ti, dp[maxsta]);
    }

    return 0;
}

UVa 11825 - Hackers' Crackdown DP, 枚举子集substa = (substa - 1)&sta 难度: 2

原文地址:https://www.cnblogs.com/xuesu/p/10434396.html

时间: 2024-12-28 08:24:54

UVa 11825 - Hackers' Crackdown DP, 枚举子集substa = (substa - 1)&sta 难度: 2的相关文章

uva 11825 Hackers&#39; Crackdown (状压dp,子集枚举)

题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有相同的n种服务),对每台计算机,你可以选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让更多的服务瘫痪(没有计算机有该项服务). 思路:(见大白70页,我的方程与大白不同) 把n个集合P1.P2.Pn分成尽量多的组,使得每组中所有集合的并集等于全集,这里的集合Pi是计算机i及其相邻计算机的集合,用cover[i]表示若干Pi的集合S中所有集合的并集,dp[s]表示子集s最多可以分成多少组,则 如果cove

UVA 11825 Hackers&#39; Crackdown 状压DP

感觉白书上的做法很神! 首先状压表示电脑之间的联通关系,然后预处理出所有关闭电脑的组合达到的状态,然后枚举每个状态并且枚举每个状态的所有子集,之后无脑递推就木有了. 关于枚举一个状态所有子集的小技巧:假设当前状态是S0 有 for s = s0; s != 0; s =  (s - 1) & s0 #include <cstdio> #include <cstring> #include <iostream> #include <map> #incl

uva 11825 Hackers&#39; Crackdown(状态压缩DP)

Hackers' Crackdown Input: Standard Input Output: Standard Output   Miracle Corporations has a number of system services running in a distributed computer system which is a prime target for hackers. The system is basically a set of N computer nodes wi

UVA 11825 Hackers&#39; Crackdown

题解: 首先将相邻点进行二进制,保存在p[i]中 然后将不同组合的p[i]组合的值记录下来,保存在cover[i]中 然后从小到大进行dp s0为集合s的子集 if(cover[ s0 ] == all - 1) f[s] = max( f[s], f[s ^ s0] + 1); 代码: #include<bits/stdc++.h> using namespace std; #define pb push_back #define mp make_pair #define se second

UVA - 11825 —— Hackers&#39; Crackdown

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18913 这道题是一道状态压缩DP的好题,有几点要注意的: 1.uva给出的题目不知道为何,题意是有些描述不清的,详见<训练指南> 2.这道题可以有很多写法,整个的dp求解和cover那个部分既可以写成记忆化搜索自顶向下,也可以自底向上来实现. #include <cstdio> #include <iostream> #include <

UVA 11825 Hackers’ Crackdown 状压DP枚举子集势

Hackers’ Crackdown Miracle Corporations has a number of system services running in a distributed computer system which is a prime target for hackers. The system is basically a set of N computer nodes with each of them running a set of Nservices. Note

状压DP [Uva 11825] Hackers’ Crackdown

Hackers’ Crackdown  Input: Standard Input Output: Standard Output   Miracle Corporations has a number of system services running in a distributed computer system which is a prime target for hackers. The system is basically a set of N computer nodes w

UVa 11825 Hackers’ Crackdown

参照大白书上面的解法,总共三个步骤,前两个步骤都较好理解.P[i]是用位表示的当选中i时,总共有0~n-1总共有多少个数字被覆盖.cover[S]则表示,当子集为S时,0~n-1中能够被覆盖的位数.若cover[S]的每位都为1,则说明子集S能对全集进行覆盖,当然可能子集S的子集就能做到这一点了. 关键的步骤是对状态转移方程的理解.书中的状态转移方程是f(S)=max{f(S0)|S0是S的子集,cover[S0]等于全集}+1,其实对于这个方程我一直感觉怪怪的,并不十分理解它的意思,虽然它最后

UVA 11825 - Hackers&amp;#39; Crackdown 状态压缩 dp 枚举子集

UVA 11825 - Hackers' Crackdown 状态压缩 dp 枚举子集 ACM 题目地址:11825 - Hackers' Crackdown 题意: 有一个由编号0~n-1的n台计算机组成的网络,一共同拥有n种服务,每台计算机上都执行着所有服务,对于每台计算机,你能够选择停止一项服务,这个行为会导致与这台计算机和与他相连的其它计算机上的这项服务都停止(原来已经停止的继续保持停止状态). 求最多能使多少个服务瘫痪(即没有不论什么一台计算机在执行这项服务). 分析: 题目说白了.就