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

题目链接:


code:

//Must so
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define mem(a,x) memset(a,x,sizeof(a))
#define inf (1<<29)
using namespace std;
typedef long long ll;
/*
    读题就读了半天=-=
    N台电脑,每台有N种服务,同时这N台电脑构成网络(输入就是电脑的关系)
    黑客要做的事是,对于每台电脑,选择1种服务去攻击
    当攻击电脑x的y服务,和x直接相连的电脑的y服务都会停止
    当一种服务在所有N台电脑都是"停止"状态的时候,我们称这种服务"崩溃"

    now ,你要做的是,对于每台电脑,选择一种服务去攻击,使得处于"崩溃"状态的服务最多
    给的N最大16,显然是要状态压缩的
    这样,对于服务i,i在编号0~n-1的n台电脑上被攻击记为1,不被攻击记为0
    state[i]记录了满足条件的状态
    所谓满足条件是说:例如001100表示在2、3号电脑上攻击可以做到使所有电脑都被攻击
    我是转化成01背包的思想=-=
    然后把这些满足条件的状态尽可能多的"装"起来
    每种状态是一个物品,物品的体积是状态二进制里面的"1",物品的价值的1
    装的时候要满足选择装进背包的状态不能有交集

*/
const int N = 1<<16;
vector<int>s[20];
int state[N+5];
int dp[N+5];
int n;
int tot;//记录满足条件的状态总数
bool ok(int x)//判断状态x是否满足条件
{
    bool vis[20] = {0};
    for (int i = 0;i < n;++i)
    {
        if ((x>>i)&1)//选择攻击第i台电脑
        {
            vis[i] = 1;
            for (int j = 0;j < s[i].size();++j)
            {
                vis[s[i][j]] = 1;//和该台被攻击的电脑直接相连的电脑的服务也停止
            }
        }
    }
    for (int i = 0;i < n;++i)//判断是否每台电脑都被攻击到了
    {
        if (!vis[i]) return 0;
    }
    return 1;
}
/*
    剪枝:比如两种状态,000111和000001,
    如果第二种状态就ok,当然没必要要第一种状态=-=
*/
vector<int>q;
void init()
{
    tot = 0;
    q.clear();
    int v = (1<<n)-1;
    for (int i = 1;i <= v;++i)
    {
        dp[i] = 0;
        bool yes = 0;
        for (int j = 0;j < tot;++j)
        {
            if ((i&q[j]) == q[j])
            {
                yes = 1;
                break;
            }
        }
        if (yes) continue;
        if (ok(i))
        {
            q.push_back(i);
            state[tot++] = i;
        }
    }
}
int main()
{
    int kas = 0;
    while (~scanf("%d",&n))
    {
        if (n==0) break;
        for (int i = 0;i < n;++i)
        {
            int m;scanf("%d",&m);
            s[i].clear();//初始化=-=
            for (int j = 0,x;j < m;++j)
            {
                scanf("%d",&x);
                s[i].push_back(x);
            }
        }
        init();
        int V = (1<<n)-1;//背包体积=-=
        for (int i = 0;i < tot;++i)
        {
            for (int j = V;j >= 0;--j)
            {
                if ((j&state[i]) == 0)//保证不能有交集=-=
                {
                    dp[j|state[i]] = max(dp[j|state[i]] ,dp[j] + 1);
                }//二进制的|运算抽象成"加"
            }
        }
        printf("Case %d: %d\n",++kas,dp[V]);
    }
    return 0;
}


你可能感兴趣的:(dp,uva,状态压缩)