[LeetCode 1025.] 除数博弈

LeetCode 1025. 除数博弈

博弈问题,非常有趣。

题目描述

Alice and Bob take turns playing a game, with Alice starting first.

Initially, there is a number N on the chalkboard. On each player's turn, that player makes a move consisting of:

  • Choosing any x with 0 < x < N and N % x == 0.
  • Replacing the number N on the chalkboard with N - x.

Also, if a player cannot make a move, they lose the game.

Return True if and only if Alice wins the game, assuming both players play optimally.

Example 1:

Input: 2
Output: true
Explanation: Alice chooses 1, and Bob has no more moves.

Example 2:

Input: 3
Output: false
Explanation: Alice chooses 1, Bob chooses 1, and Alice has no more moves.

Note:

  1. 1 <= N <= 1000

解题思路

这道题是说,给定一个初值 N,然后先手给出 N 的一个因数 x,再用 N-x 替换数字,交由对方操作;直到一方拿到 1 再也找不到比自身小的因数算是输掉比赛。
双方都足够聪明,会选取对自己最有利的操作,给出任意一个 N 会是输是赢。

思路一:DP

我们去枚举每一个因子,如果存在一个因子可以让对方输掉比赛,我们也就能赢;否则我们就要输掉比赛。

思路二:数学构造法

如果我们就是最聪明的人,能一下子找到最佳策略,那我们也可以很快直到怎么操作怎么赢。

注意到:

  1. 拿到 1 的必输,谁能最先拿到 2 谁赢;
  2. 拿到奇数的,因为因数只有奇数,对手必将获得偶数;
  3. 拿到偶数的,只要一直选1这个因数,对手将一直被迫拿奇数,自己一直稳拿偶数,直到拿到 2 获得胜利。

结论也就来了,拿到偶数的,够聪明就一直用因子 1,稳赢;拿到奇数的,选哪个奇数都是输!

你以为人定胜天,其实你根本没得选,开局的时候输赢就已经定了……

参考代码

两种思路的代码如下:

/*
 * @lc app=leetcode id=1025 lang=cpp
 *
 * [1025] Divisor Game
 */

// @lc code=start
class Solution {
public:
/*
    bool divisorGame(int N) {
        vector<bool> dp(N+1);
        dp[1] = false;
        dp[2] = true;
        dp[3] = false;
        for (int i=4; i<=N; i++) {
            bool canWin = false;
            for (int j=1; j<i; j++) {
                if (i % j == 0) {
                    if (!dp[i-j]) {
                        canWin = true;
                        break;
                    }
                }
            }
            dp[i] = canWin;
        }
        return dp[N];
    } // AC
*/
    bool divisorGame(int N) {
        return (N % 2) == 0;
    } // AC
};
// @lc code=end
posted @ 2021-03-10 12:52  与MPI做斗争  阅读(51)  评论(0编辑  收藏  举报