1025.除数博弈 -----力扣每日打卡Day5

1.题目

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

  • 选出任一 x,满足 0 < x < N 且 N % x == 0 。
  • 用 N - x 替换黑板上的数字 N 。

如果玩家无法执行这些操作,就会输掉游戏。
只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。
示例 1:

输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。

示例 2:

输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。

提示: 1 <= N <= 1000
C语言函数头:

bool divisorGame(int N){}

来源:力扣(LeetCode)戳我前往题目

2.题目分析

老实说,这题第一眼看到我是没办法做的。这种博弈题,如果正向观察,因为是选择任一的X,无法确定的,如果按照正向思维来做是很难考虑的。所以,我们可以反向思维,从最小的开始看。
这种一个个从小倒推回去,表示的一种状态,我们可以用动态规划的方法。首先确定初始条件

  • dp[1] = flasedp[2] = ture .通过示例可以得出。当N等于1的时候,爱丽丝会输;当N 等于2的时候,爱丽丝能赢。

然后就是迭代规律

  • 如果下一个数中的约数中,存在 dp[i-j] = false,也就是下一个走得人,会输那么这个数也必然 true

3.动态规划代码实现

bool divisorGame(int N){
    int dp[1100];
    dp[1] = 0;
    dp[2] = 1;
    //从小到大一步步进行判断
    for(int i = 3; i <= N; i++)
    {
        int flag = 0;
        //约数中如果有dp[i-j] = false 的,那爱丽丝就能赢,动态规划
        for(int j = i-1; j > 0; j--){
            if(i % j == 0 && dp[i-j] == 0){
                dp[i] = 1;
                flag = 1;
            }
        }
        if(flag == 0)
        dp[i] = 0;
    }
    return dp[N] == 1;
}

在这里插入图片描述

你以为这就完了,NO!

4.究极解答 —— 找规律

这道题还有一种找规律!如果我们看到这种题实在是没有头绪,可以找找规律,从小开始找。

  1. 当 N = 1.爱丽丝输了。
  2. 当 N = 2.爱丽丝赢了。
  3. 当 N = 3.爱丽丝输了。
  4. 当 N = 4.爱丽丝赢了。爱丽丝选择1,余3,鲍勃选择1,余2,爱丽丝选1,赢了。
  5. ……
    可以发现一波,如果N是偶数,爱丽丝就赢,如果N是奇数爱丽丝就输。

证明

  1. N=1 和 N = 2 时结论成立。
  2. N >2 时,假设 N ≤ k 时该结论成立,则 N = k + 1 时:
  • 如果 k 为偶数,则 k + 1为奇数,x 是 k + 1的因数,只可能是奇数,而奇数减去奇数等于偶数,且 k + 1 - x ≤ k,故轮到 Bob 的时候都是偶数。而根据我们的猜想假设 N ≤ k 的时候偶数的时候先手必胜,故此时无论 Alice 拿走什么,Bob都会处于必胜态,所以 Alice 处于必败态。

  • 如果 k 为奇数,则 k+1 为偶数,x 可以是奇数也可以是偶数,若 Alice 减去一个奇数,那么 k + 1 − x 是一个小于等于 k的奇数,此时 Bob 占有它,处于必败态,则 Alice 处于必胜态。

综上所述,这个猜想是正确的。

代码:

bool divisorGame(int N) {
    return N % 2 == 0;
}

第二种解答来源:力扣(LeetCode)戳我前往官方解答

猜你喜欢

转载自blog.csdn.net/qq_46293423/article/details/107556908
今日推荐