题目链接: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;
}
};