2023河南萌新联赛第(五)场:郑州轻工业大学--买爱心气球

题目链接:A-买爱心气球_2023河南萌新联赛第(五)场:郑州轻工业大学 (nowcoder.com)

题目描述

Alice 和 Bob 是一对竞技编程选手,他们路过了一家气球店,发现有 m 个大爱心气球和 n 个小爱心气球。他们决定玩一个游戏,游戏规则如下:

  1. Alice 先手拿球,两人轮流进行。
  2. 每个人在自己的回合只能选择一种类型的气球。
  3. 对于大爱心气球,每次拿取可以选择取 5 个、2 个或 1 个。
  4. 对于小爱心气球,每次拿取可以选择任意数量 (不含0个)。

游戏终止的条件是当所有的气球都被拿取完毕,最后一个球被拿取的人即为获胜者。

假设两人都足够聪明并采取最优策略,请问谁将获胜?

输入描述:

本题包含多组数据

第一行包含一个正整数 ,代表测试用例的组数。

对于每组数据:

输入一行包含两个正整数 。 

数据保证 m 和 n 不同时为 0

输出描述:

对于每组数据:

输出一行一个字符串,如果 Alice 获胜,输出 "Alice"

否则如果 Bob 获胜,输出 "Bob" (输出不含引号)。

示例1

输入

3

3 1

3 3

5 2

输出

Alice

Alice

Bob

思路:

这个题是一个博弈的问题,看不出规律就可以使用SG来解决,首先不会SG的可以先去学一手SG,很简单。

最后的必胜的终态有两种:

(1)当m一次就可以被取完,n已经没有的时间,必胜

(2)当m取完以后,n还有剩余就可以一次取完,必胜

SG函数:

int sg(int m,int n){
    if(mp.find({m,n}) != mp.end())//记忆化,会使的程序快很多
        return mp[{m,n}];
    set<int>st;//设立一个set来存他所有子状态的SG值
    if(m == 1 || m == 2 || m == 5){//必胜终态
        if(n == 0)return 1;
    }
    if(m == 0){//必胜终态
        if(n != 0)return 1;
    }
    //模拟取气球的过程,找出其所有的子状态
    for(int i = 1;i <= n;i++){
        st.insert(sg(m,n - i));
    }
    if(m >= 5){
        st.insert(sg(m - 5,n));
        st.insert(sg(m - 2,n));
        st.insert(sg(m - 1,n));
    }
    else if(m >=2){
        st.insert(sg(m - 2,n));
        st.insert(sg(m - 1,n));
    }
    else if(m >= 1){
        st.insert(sg(m - 1,n));
    }
    //找到最小的没有出现的值
    for(int i = 0;;i++){
        if(st.count(i) == 0){
            mp[{m,n}] = i;
            return i;
        }
    }
}

然后就可以固定m,跑n,就会很神奇的发现,其实n只有在1和2的情况下会出现先手必败的状态,在找一下规律会发现当m自增的时间,这个先手必败状态出现的 n 的值是循环出现的,先出现在1,在出现在2,在没有必败,在出现在1,出现在2......

所以这个规律就相当的明显了,当 m \% 3 = n  的时间是先手必败的状态

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值