[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 <= N <= 1000
解题思路
这道题是说,给定一个初值 N,然后先手给出 N 的一个因数 x,再用 N-x 替换数字,交由对方操作;直到一方拿到 1 再也找不到比自身小的因数算是输掉比赛。
双方都足够聪明,会选取对自己最有利的操作,给出任意一个 N 会是输是赢。
思路一:DP
我们去枚举每一个因子,如果存在一个因子可以让对方输掉比赛,我们也就能赢;否则我们就要输掉比赛。
思路二:数学构造法
如果我们就是最聪明的人,能一下子找到最佳策略,那我们也可以很快直到怎么操作怎么赢。
注意到:
- 拿到 1 的必输,谁能最先拿到 2 谁赢;
- 拿到奇数的,因为因数只有奇数,对手必将获得偶数;
- 拿到偶数的,只要一直选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