[LeetCode] 1025、除数博弈

题目描述

爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:

  • 选出任一 x,满足 0 < x < NN % 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] = Falsedp[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];
    }
    
};
发布了390 篇原创文章 · 获赞 576 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/ft_sunshine/article/details/103838161