Hacker's Crackdown(UVa 11825)状态压缩dp+数学模型

本文介绍了一种使用状态压缩动态规划解决黑客入侵问题的算法。该算法的目标是在虚拟网络中尽可能多地瘫痪服务,通过将问题转化为集合覆盖问题,并利用二进制表示与状态压缩DP求解最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来自《算法竞赛入门经典训练指南》

1.题目原文

假如你是一个黑客,侵入了n台计算机(编号为0,1,2,……n-1)的网络。一共有n种服务,每台计算机都运行着这种服务。对于每台计算机,你都可以选择一项服务,终止这台计算机和所有与它相邻的计算机的该项服务(如果一些服务已经停止,会一直停止下去)。目标是让尽量多的服务完全瘫痪(没有任何计算机运行该项服务).

2.解题思路

数学模型是:把n个集合P[1],P[2],……P[n]分成尽量多组,使得每组中所有集合的并集等于全集。对于本题,集合P[i]就是计算机i及其相邻的计算机的集合,每组对应题目中的一项服务。
集合的并集,用按位或;集合的差集,用按位异或。
显然用二进制表示集合。下面用状态压缩dp来解决这道题。
用cover[S]表示若干P[i]的集合S中所有P[i]的并集。
用f(S)表示子集S最多可以分多少组,则f(S)=max(f(S-S0)}+1.其中S0是S的子集,且cover[S0]等于全集。
这题有一个重要的技巧,枚举S的所有子集S0。

如何分析算法的时间复杂度?它等于全集{1,2,3,……,n}的所有子集的个数,显然就是sum{C(n,k)*2^k}=3^n。

3.AC代码

#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include<cmath>
#include<bitset>
#include<sstream>
#include<stack>
using namespace std;
#define INF 0x7fffffff
typedef long long ll;
const int maxn=(1<<16)+10;
//用cover[S]表示若干P[i]的集合S中所有P[i]的并集。
//用f(S)表示子集S最多可以分多少组
int P[maxn],cover[maxn],f[maxn];
int n,m;

int main()
{
    int kase=0;
    while(scanf("%d",&n)!=EOF&&n){
        for(int i=0;i<n;i++){
            scanf("%d",&m);
            P[i]=1<<i;
            while(m--){
                int x;
                scanf("%d",&x);
                P[i]|=(1<<x);
            }
        }

        for(int S=0;S<(1<<n);S++){
            cover[S]=0;
            for(int i=0;i<n;i++){
                if(S&(1<<i)){
                    cover[S]|=P[i];
                }
            }
        }

        f[0]=0;
        int All=(1<<n)-1;
        for(int S=1;S<(1<<n);S++){
            f[S]=0;
            //枚举集合S的所有子集
            for(int S0=S;S0;S0=(S0-1)&S){
                if(cover[S0]==All){
                    f[S]=max(f[S],f[S^S0]+1);
                }
            }
        }

        printf("Case %d: %d\n",++kase,f[All]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值