NKOJ3720 黑客攻击 [状态压缩][背包DP]

NKOJ3720 黑客攻击:状态压缩与背包DP解法
本文介绍了如何解决NKOJ3720黑客攻击问题,通过状态压缩和背包动态规划策略,找到使服务完全瘫痪的最优攻击方案。问题描述涉及终止计算机服务,影响相邻计算机,并求解最大瘫痪服务数量。解题思路包括将计算机关系转化为状态编码,并利用动态规划寻找覆盖所有服务器的攻击子集。

NKOJ3720 黑客攻击 [状态压缩][背包DP]

问题描述

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

输入格式

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

输出格式

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

样例输入

3
2 1 2
2 0 2
2 0 1
4
1 1
1 0
1 3
1 2
0

样例输出

Case 1: 3
Case 2: 2

解法

范围这么小,当然是考虑状压或者搜索了。这里又密切和每台电脑的状态相关联,基本上就是状压了。

首先要把每台电脑的关系给压出来。比如样例Case 2中(11)(11)表示0和1号电脑相连。几台电脑相连意味着其中的任意一台电脑被停止,那么与它相连的所有电脑的任意一项服务都会被停止。

题目要求完全瘫痪,因此我们要想办法凑出(11…1)(n个1)的状态。任选几台电脑,只要与它们相连的电脑构成的集合(并集)覆盖了所有服务器,那么攻击这些电脑就可以使得服务器完全瘫痪。

设定状态f[s]f[s]表示攻击集合ss中的电脑最多能够使得多少服务器完全瘫痪。这时只要找出s尽可能多的子集(每个子集的攻击范围都能覆盖所有服务器)即可。这表示为方程就是:f[s]=max{f[s^ss]}+1 (ss是s的子集 且 ss的攻击范围覆盖了所有服务器)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int A[20],B[66000],f[66000];
//A[i]表示第i台电脑与哪些电脑相连
//B[i]用来表示攻击s集合中的能够使得哪些服务器瘫痪
int main(){
    int n,cnt=0;scanf("%d",&n);
    while(n){
        cnt++;
        for(int i=0;i<n;i++){
            int t,tt=0;scanf("%d",&t);
            tt|=(1<<i);
            for(int j=1;j<=t;j++){
                int ttt;scanf("%d",&ttt);
                tt|=(1<<ttt);
            }
            A[i+1]=tt;
        }
        int nn=(1<<n)-1;
        for(int s=1;s<=nn;s++)
            for(int i=0;i<n;i++)
                if(s&(1<<i))B[s]|=A[i+1];
        for(int i=1;i<=nn;i++)
            for(int j=i;j;j=(j-1)&i)
                if(B[j]==nn)f[i]=max(f[i],f[i^j]+1);
        printf("Case %d: %d\n",cnt,f[nn]);
        memset(f,0,sizeof(f));
        memset(A,0,sizeof(A));
        memset(B,0,sizeof(B));
        scanf("%d",&n);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值