• 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;
    }





  • 相关阅读:
    C++拷贝构造函数(深拷贝,浅拷贝)
    C++标准库和标准模板库
    MFC 定制控件(Customize Control) 及 MFC CWnd和WIN32 HWND关联方法
    MFC 对象与Win32 SDK 句柄的映射关系
    关于函数返回值的几种情况
    CreateWaitableTimer和SetWaitableTimer函数
    关于C++/C中防止头文件的重复包含的解决办法
    MFC 分割窗体(Splitter Windows)
    MFC中对话框的数据交换(DDX)和数据校验(DDV)
    MFC 消息映射表 及 相关宏定义
  • 原文地址:https://www.cnblogs.com/riskyer/p/3353215.html
Copyright © 2020-2023  润新知