Leetcode 2029. 石子游戏 IX

题目链接:2029. 石子游戏 IX

Alice 和 Bob 再次设计了一款新的石子游戏。现有一行 n 个石子,每个石子都有一个关联的数字表示它的价值。给你一个整数数组 stones ,其中 stones[i] 是第 i 个石子的价值。

Alice 和 Bob 轮流进行自己的回合,Alice 先手。每一回合,玩家需要从 stones 中移除任一石子。

如果玩家移除石子后,导致 所有已移除石子 的价值 总和 可以被 3 整除,那么该玩家就 输掉游戏 。
如果不满足上一条,且移除后没有任何剩余的石子,那么 Bob 将会直接获胜(即便是在 Alice 的回合)。
假设两位玩家均采用 最佳 决策。如果 Alice 获胜,返回 true ;如果 Bob 获胜,返回 false 。

示例 1:

输入:stones = [2,1]
输出:true
解释:游戏进行如下:
- 回合 1:Alice 可以移除任意一个石子。
- 回合 2:Bob 移除剩下的石子。 
已移除的石子的值总和为 1 + 2 = 3 且可以被 3 整除。因此,Bob 输,Alice 获胜。

题解:

对于石子总价值产生影响的可以归结为3类石子

第一类是与3取余之后为0的石子,对和不产生影响,但是会影响先后手

第二类是与3取余之后为1的石子

第三类是与3取余之后为2的石子

函数 isWin 作用是判断当前有x个值为1的石子,当前有y个值为2的石子,0 个值为0的石子,当前石子和为val,Alice 先手是否能赢。

情况1 如果不存在第一类石子,即取余之后为0的石子不存在,那么直接调用isWin函数判断

情况2 如果存在第一类石子,如果第一类石子数量大于等于2,那么将数量对2取余,因为一类石子对石子和不产生影响,Alice和Bob先后选择一类石子,局面会恢复到之前的局面。

所以只看取余之后的结果,如果余数等于1,需要特殊判断一下,

        有一个人取一个二类石子,另一个人取一类石子

        有一个人取一个三类石子,另一个人取一类石子

        至于为什么会有一个取一类石子,可以这么理解,假设在不适用一类石子,Alice先手必赢的话,Bob肯定是会选择使用一类石子,将局面变化一下;假设在不适用一类石子,Alice先手必输的话,Alice 也需要选择一类石子,将局面变化一下。

class Solution {
public:
    bool stoneGameIX(vector<int>& stones) {
        int x =0, y = 0, z = 0;
        for(auto & item : stones){
            if(item % 3 == 0)
                ++z;
            if(item % 3 == 1)
                ++x;
            if(item % 3 == 2)
                ++y;
        }

        z %= 2;

        if(z == 0)
            return isWin(x,y,0);
        else{
            return isWin(x-1, y, 1) || isWin(x, y-1, 2);
        }
        
        return false;
    }
    bool isWin(int x, int y, int val){
        if(x == 0 && y == 0)
            return false;

        if(val == 0){
            //Alice 拿一个值为1的石子, Bob只能选择值为2的石子
            if(x == 1)
                return y > 0;
            //Alice 拿一个值为2的石子, Bob只能选择值为1的石子
            else if(y == 1)
                return x > 0;
            else{
                //Alice 拿一个值为1的石子, Bob只能选择值为1的石子,递归判断
                if(isWin(x-2, y, 2))
                    return true;
                //Alice 拿一个值为2的石子, Bob只能选择值为2的石子,递归判断
                if(isWin(x, y-2, 1))
                    return true;

                return false;
            }
        }
        else if(val == 1){
            //Alice 此时只能拿一个值为1的石子,如果值为1的石子为0,或则值为1的石子数量为1且值为2的石子数量为0,判断输
            if(x <= 0 || (x == 1 && y == 0))
                return false;
            //Alice 此时只能拿一个值为1的石子,如果值为1的石子大于2,且值为2的石子数量为0,判定赢
            if(x >= 2 && y == 0)
                return true;
            //Alice 拿一个值为1的石子, Bob只能选择值为2的石子,递归判断
            if(isWin(x-1, y-1, val))
                return true;

            return false;
        }
        else if(val == 2){
            //Alice 此时只能拿一个值为2的石子,如果值为2的石子为0,或则值为2的石子数量为1且值为1的石子数量为0,判断输
            if(y <= 0 || (y == 1 && x== 0))
                return false;
            //Alice 此时只能拿一个值为2的石子,如果值为2的石子大于2,且值为1的石子数量为0,判定赢
            if(y >= 2 && x == 0)
                return true;
            //Alice 拿一个值为2的石子, Bob只能选择值为1的石子,递归判断
            if(isWin(x-1, y-1, val))
                return true;

            return false;
        }
        return false;
    }
};

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值