• 2019年FJNU低编赛 G题(dfs博弈)


    ###题目链接###

    题目大意:

    有一个 0 ~ n+1 的数轴,Alice 站在 0 点处,Bob 站在 n+1 点处。在 1 ~ n 上各有着权值。 Alice 每次向右移动 1 格或两格 ,Bob 每次向左移动 1 格或 2 格(他们一定要移动),Alice 移动到 n+1 处停止,Bob 移动到 0 处停止,直到他们都停止的时候,此时若 Alice 所经过的数值总和大于 Bob 的数值总和,则 Alice 胜出,反则 Bob 胜出。Alice 先出手,两人足够聪明,走到的数值必须拿走,而走到过的数值不能再被拿走。

    分析:

    1、显然是博弈题。

    2、dfs 枚举所有可能,当 Alice 出手时,有两种走法(走一步或两步)。比如 Alice 走一步后,枚举 Bob 走到的地方(也只有两种走法),然后判断是否 Bob 无论怎样走, 此时 Alice 必赢,则 “此刻 Alice 走一步” 为必胜态,因为若 Alice 走这一步之后, Bob 无论怎么操作都无法获胜,则此时为必胜态。

    3、故枚举 Alice 的两次走法,假如此时 Alice 处于位置 x ,若此刻走到 u 可以使得自身处于必胜态,则返回 true ,告诉 dfs 的上一层中,走到 x 处可以转化为必胜态。

    博弈点分析:假如此刻位置为 x ,现在两种走法可以使得 x 走到 u1 或者 u2。若 u1 与 u2 同时为必胜点,则 x 处也为必胜点;若 u1 是必胜点,u2 是必败点,则 x 处也为必胜点,因为 选手足够聪明,走到 x 处后会走到 u1 处,故 x 为必胜点;若 u1 与 u2 同为必败点,则 x 也为必败点。这就是为什么 必胜点可以转化为必败点或必胜点,而必败点只能转化为必败点。

    细节处理:

    1、此题不应该 vis 设为 bool 类型,因为走过的点会重复,不好判断。

    2、最好走到临界点的时候特判(x==n+1 以及 y==0)。

    代码如下:

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    int t,n;
    int a[18];
    int tox[2]={1,2};
    int toy[2]={-1,-2};
    int vis[18];
    bool dfs(int x,int y,int res,int ans){
        if(x==n+1&&y==0) return res>ans;
        bool q;
        for(int i=0;i<2;i++){
            q=true;
            int u,res1;
            if(x==n+1) u=x,res1=0;
            else{
                u=x+tox[i];
                if(u>n+1) continue;
                vis[u]++;
                res1=(vis[u]==2?0:a[u]);
            }
            for(int j=0;j<2;j++){
                int v,ans1;
                if(y==0) v=y,ans1=0;
                else{
                    v=y+toy[j];
                    if(v<0) continue;
                    vis[v]++;
                    ans1=(vis[v]==2?0:a[v]);
                }
                bool w=dfs(u,v,res+res1,ans+ans1);
                if(y!=0) vis[v]--;
                if(!w) {
                    q=false;
                    break;
                }
            }
            if(x!=n+1) vis[u]--;
            if(q) return true;
        }
        return false;
    }
    int main()
    {
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++) scanf("%d",&a[i]);
            a[0]=a[n+1]=0;
            if(dfs(0,n+1,0,0)) printf("Alice
    ");
            else printf("Bob
    ");
        }
    }
  • 相关阅读:
    错误:Char 26: fatal error: reference to non-static member function must be called
    【C++】去除字符串string中的空格(两头空格、所有空格)
    【C/C++】字符串string与字符数组char*的相互转换
    【C++】if-else编程陷阱
    【数据结构与算法】《剑指offer》学习笔记----第一章、第二章 基础知识(含1-15题)
    LeetCode运行报错: reference binding to null pointer of type 'value_type'
    【深度学习机配置】Dell服务站各组件型号记录
    【C++、二分法】LeetCode744. 寻找比目标字母大的最小字母
    Python视频抽帧成图片
    Windows10自带的录屏软件,十分强大
  • 原文地址:https://www.cnblogs.com/Absofuckinglutely/p/12008807.html
Copyright © 2020-2023  润新知