UVALive 4959 Jumping monkey


题意就是:

一个猎人在森林里捕猎。

然后有只猴子,喜欢躲树的后边,猎人看不见它

然后给出了一张图,表示有哪些树是相邻的。

数据保证任意图中两个树都可以直接或间接的到达


猎人有一个枪,每次他可以选择一颗树,然后射子弹。如果猴子躲那个树后边,就被打死了。

但是如果没躲那个树后边,猴子会利用猎人换子弹的时间立刻蹦到这个树相邻的树上躲藏,

问猎人应该怎样击打树才能保证必然能击打中猴子。


比如第一个样例,

猎人只要在0号树上击打两次即可,因为猴子如果没被打中,必然会往旁边的树跑


然后可以看到的是

n的范围很小。

可以考虑使用状态压缩DP


刚开始因为猴子是有可能出现在所有树上的。

所以状态为(1 << n) - 1

我们的目标是 让猴子出现的可能消灭为0状态


对于猴子每次枪响后转移

对于一个点,必然是其周围所有的点都有可能会跳到这个点上

那么我们每次先将猴子转移后的状态求出来。

选择一个尽量小的点毙掉这颗树上的猴子。

因为没有什么顺序

所以将状态加入队列中来转移

如果转移到了0状态。

因为我们每次都尽量小的点去毙掉

所以能保证字典序,中间过程记录下路径,最后输出即可


#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <vector>
#define eps 1e-8
#define INF 111111111
using namespace std ;
int n, m;
queue<int>q;
vector<int>res;
int st[33];
int pre[(1 << 21) + 5];
int num[(1 << 21) + 5];
int gao()
{
    q.push((1 << n) - 1);

    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        int nxt = 0;
        for(int i = 0; i < n; i++)
        {
            if(u & (1 << i))
                nxt |= st[i];
        }
        for(int i = 0; i < n; i++)
            if(nxt & (1 << i))
            {
                int k = nxt ^ (1 << i);
                if(pre[k] == -1)
                {
                    pre[k] = u;
                    num[k] = i;
                    q.push(k);
                    if(k == 0) return 1;
                }
            }
    }
    return 0;
}
int main()
{
    int x, y;
    while(scanf("%d%d", &n, &m) != EOF)
    {
        if(!n && !m) break;
        memset(st, 0, sizeof(st));
        while(!q.empty()) q.pop();
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d", &x, &y);
            st[x] |= (1 << y);
            st[y] |= (1 << x);
        }
        if(n == 1)
        {
            printf("1: 0
");
            continue;
        }
        if(m >= n)
        {
            puts("Impossible");
            continue;
        }
        memset(pre, -1, sizeof(pre));
        int k = gao();
        if(k == 0)
            puts("Impossible");
        else
        {
            res.clear();
            int top = 0;
            while(top != (1 << n) - 1)
            {
                res.push_back(num[top]);
                top = pre[top];
            }
            printf("%d:", res.size());
            for(int i = res.size() - 1; i >= 0; i--) printf(" %d", res[i]);
            puts("");
        }
    }
    return 0;
}





原文地址:https://www.cnblogs.com/riskyer/p/3353215.html