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] = flase
,dp[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.究极解答 —— 找规律
这道题还有一种找规律!如果我们看到这种题实在是没有头绪,可以找找规律,从小开始找。
- 当 N = 1.爱丽丝输了。
- 当 N = 2.爱丽丝赢了。
- 当 N = 3.爱丽丝输了。
- 当 N = 4.爱丽丝赢了。爱丽丝选择1,余3,鲍勃选择1,余2,爱丽丝选1,赢了。
- ……
可以发现一波,如果N是偶数,爱丽丝就赢,如果N是奇数爱丽丝就输。
证明:
- N=1 和 N = 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)戳我前往官方解答
来源:oschina
链接:https://my.oschina.net/u/4398470/blog/4437193