UVa 11825 Hackers' Crackdown (状态压缩DP)

本文针对UVa11825题目“Hackers’Crackdown”,介绍了一种通过递推求解最优分组策略的方法,旨在最大化服务瘫痪的数量。通过预处理和递归状态转移方程,解决了复杂的服务终止问题。

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

UVa 11825 Hackers’ Crackdown

题目大意:

侵入n台计算机,每台计算机有m个相邻计算机.对于一台计算机,可以选择终止其一种服务,相邻计算机也会受到影响停止该种服务,问最多能有多少种服务完全瘫痪(也就是说要让所有计算机均停止该种服务).

题目分析:

一台计算机只能终止一种服务,若用P[i]表示i号计算机的相邻计算机集合(包括i号计算机本身),那么实质上问题就是在每一组的P的并集为全集的前提下,将如何分组,使得组数尽可能多.
那么若用S表示P集合的取法,ALL表示全集,S0表示为S子集,其补集为S^S0.
则有,若S0=ALL,那么S0就可以作为一种分组.
那么S的分组种数=S0的分组种数+S^S0的分组种数.
设f[S]表示S集合最多能分成多少组,则可以表示为f[S]=1+f[S^S0].
所以转移方程f[S]=max{1+f[S^S0]|S=ALL}

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

const int maxn=16;

int P[maxn],cover[1<<maxn],f[1<<maxn],n;
//P[i]表示第i号计算机的相邻集合 
//S表示P的集合,那么cover[S]表示S包含的计算机集合,f[S]表示S集合下的种类数 

int main()
{
    int kase=0;
    while(scanf("%d",&n)==1&&n) {
        for(int m,i=0;i<n;i++) {//预处理每台计算机的集合 
            scanf("%d",&m);
            P[i]=1<<i;
            for(int t,j=0;j<m;j++) scanf("%d",&t),P[i]|=(1<<t);
        }
        int ALL=(1<<n)-1;
        for(int S=0;S<=ALL;S++) {//预处理S包含的计算机集合 
            cover[S]=0;
            for(int i=0;i<n;i++) if(S&(1<<i)) cover[S]|=P[i];
        }
        for(int S=0;S<=ALL;S++) {//递推求解 
            f[S]=0;
            for(int S0=S;S0;S0=(S0-1)&S)//枚举子集的技巧 
                if(cover[S0]==ALL) f[S]=max(f[S],f[S^S0]+1);//集合S由子集S0和S0的补集S^S0并而来 
                //若S0是全集ALL单独能构成一种合法方案加上其补集能构成的方案数,即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、付费专栏及课程。

余额充值