题目描述
爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。最初,黑板上有一个数字 N
。在每个玩家的回合,玩家需要执行以下操作:
- 选出任一
x
,满足0 < x < N
且N % x == 0
。 - 用
N - x
替换黑板上的数字N
。
如果玩家无法执行这些操作,就会输掉游戏。只有在爱丽丝在游戏中取得胜利时才返回 True
,否则返回 false
。假设两个玩家都以最佳状态参与游戏。
解题思路
博弈问题,两种解题思路:
-
归纳法:神仙解法,记一下这个解法即可。
- 首先明确:最终结果应该是占到 2 的赢,占到 1 的输;
- 若当前为奇数,奇数的约数只能是奇数或者 1,因此下一个一定是偶数;
- 若当前为偶数, 偶数的约数可以是奇数可以是偶数也可以是 1,因此直接减 1,则下一个是奇数;
- 因此,偶则赢(爱丽丝只需一直选1,使鲍勃一直面临N为奇数的情况,这样爱丽丝稳赢),奇则输(爱丽丝第一次选完之后N必为偶数,那么鲍勃只需一直选1就会稳赢)。
-
动态规划:正常思路
-
设
dp[n]
表示:当黑板上的数字为n
时,此时正在玩游戏的人的输赢情况。(必输或者必赢,因为题目中说了“两个玩家都以最佳状态参与游戏”) -
如果在Alice取了数字
x
,,那么显然dp[n]
与dp[n-x]
输赢情况相反。x
可以取的值很多,只要dp[n-x_i]
中任意一个为False
, 那么dp[n]
肯定为True
,否则dp[n]
肯定为False
。 -
初始化:
dp[1] = False
,dp[2] = True
。 -
返回值:
dp[N]
-
参考代码
归纳法
class Solution:
def divisorGame(self, N: int) -> bool:
return N % 2 == 0
动态规划法
class Solution {
public:
bool divisorGame(int N) {
if(N == 1) return false;
if(N == 2) return true;
bool dp[N + 1];
memset(dp, 0, sizeof(dp));
dp[1] = false, dp[2] = true;
for(int i = 3; i <= N; i++){
for(int j = 1; j < i; j++){
if(i % j == 0 && !dp[i - j]){
dp[i] = true;
break;
}
}
}
return dp[N];
}
};
来源:CSDN
作者:aift
链接:https://blog.csdn.net/ft_sunshine/article/details/103838161