1025. 除数博弈(C++)

题目

爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。

最初,黑板上有一个数字 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

分析与题解

自底向上递推

我们先考虑简单的一些基本情况:

  • N=1 的时候,区间 (0, 1) 中没有整数是 n 的因数,所以此时 Alice 败。
  • N=2 的时候,Alice 只能拿 1,N变成 1,Bob 无法继续操作,故 Alice 胜。
  • N=3 的时候,Alice 只能拿 1,N 变成 2,根据 N=2 的结论,我们知道此时 Bob 会获胜,Alice 败。
  • N=4 的时候,Alice 能拿 1 或 2,如果 Alice 拿 1,根据 N=3 的结论,Bob 会失败,Alice 会获胜。
  • N=5 的时候,Alice 只能拿 1,根据 N=4 的结论,Alice 会失败。

动态规划的重点是找到状态转移方程。我们先确定题目的状态,因此定义res[i]表示数字为i时先手的胜负情况:

  • true表示先手胜利
  • false表示先手失败

如果AC在res[k]的情况时,她对于多种公约数的情况中,存在一种情况使得变为res[m](m<k)为负,即Bob此时先手时必输,那么就认为res[k]的值为true。这里就涉及遍历非本身的其他公约数的情况。

题目规定两人状态均最佳,因此只要存在一种胜利手段,AC就能够达成

相反,如果遍历公约数仍未找到,我们就认为AC没有制胜的手段。

代码如下:

class Solution {
public:
    bool divisorGame(int N) {
        if(N==1) return false;
        if(N==2) return true;
        //res[i]表示在数字为i时,先手人的胜负
        vector<int> res(N+1, false);
        //先确定特殊情况的结果
        res[1] = false;
        res[2] = true;
        for(int i=3;i<=N;i++){
            for(int j=1;j<i;j++){
                //如果在AC先手后,i-j此时操作(Bob)的胜负
                if(i%j==0 && res[i-j]==false){
                    res[i]=true;
                    //因为状态最佳,只要出现必胜情况,即可退出子循环
                    break;
                }
                    
            }
        }
        return res[N];
    }
};

找规律(神仙做法)

  • N=1 的时候,区间 (0, 1) 中没有整数是 n 的因数,所以此时 Alice 败。
  • N=2 的时候,Alice 只能拿 1,N变成 1,Bob 无法继续操作,故 Alice 胜。
  • N=3 的时候,Alice 只能拿 1,N 变成 2,根据 N=2 的结论,我们知道此时 Bob 会获胜,Alice 败。
  • N=4 的时候,Alice 能拿 1 或 2,如果 Alice 拿 1,根据 N=3 的结论,Bob 会失败,Alice 会获胜。
  • N=5 的时候,Alice 只能拿 1,根据 N=4 的结论,Alice 会失败。
  • N=6 的时候,Alice能拿1或2或3,如果Alice拿1,根据N=5的结论,此时Bob先手必定失败,Alice会获胜。

通过上述的简单情况的罗列,你兴许可以推断出,N为偶数时Alice能赢,而N为奇数时Alice会输。

毕竟只是大胆的猜测,接下来可以通过数学归纳法尝试证明该结论。

(1)特殊情况

当N=1时,为奇数,Alice失败

当N=2时,为偶数,Alice胜利

(2)n>2时,假设n<=K时该假设成立

通过以上的罗列知道k值至少为6

则当N=k+1时,又根据K的奇偶性进行分类讨论:

①K为偶数时,假设x是k+1的因数,x必然为奇数(k+1为奇数,奇奇为奇),那么k+1-x<k,此时(k+1-x)满足我们之前提出的假设,奇-奇=偶,所以(k+1-x)为偶数,此时Bob先手并且数字为偶数,所以Alice在奇数的情况必输。

②K为奇数时,假设x是K+1的因数,x可能为奇数或偶数,我们只需要找到一种可行的制胜手段即可。x为奇数时,(k+1-x)为奇数,此时Bob先手必然为负,所以Alice必然胜利。

得证。

所以最终题目就变成了判断N是奇偶性即可,代码如下:

class Solution {
public:
    bool divisorGame(int N) {
        if(N%2==0) return true;
        else return false;
    }
};
posted @ 2020-09-15 19:45  脱线森林`  阅读(138)  评论(0编辑  收藏  举报