Leetcode初学——动态规划算法“除数博弈”(假 )
题目
爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。
最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:
选出任一 x,满足 0 < x < N 且 N % x == 0 。
用 N - x 替换黑板上的数字 N 。
如果玩家无法执行这些操作,就会输掉游戏。
只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。
示例 1:
输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。
示例 2:
输入:3
输出:false
题解
这道题真的很有意思,可以说是我目前遇到过的最有意思的题了,虽然它被打上了动态规划的标签,我觉得它其实就是一个脑筋急转弯,题目字面意思很容易理解,找除本身外的因数,找不到就输了。但是它实际做起来其实我觉的是比较的有难度的,通常做动态规划题的思路一般是从小的开始一点点扩大找规律,但是本题不同,本题类似于下棋,每个人其实都有不同的解法,同一个题目不同的解法很有可能就得出不同的结果,打个比方,当N=25时(A为爱丽丝,B为鲍勃):
25 | 20 | 16 | 12 | 9 | 6 | 3 | 2 |
5 | 4 | 4 | 3 | 3 | 3 | 1 | 1 |
A | B | A | B | A | B | A | B |
可以看出,最后爱丽丝无路可走失败了,但是换一种走法:
25 | 20 | 15 | 10 | 5 | 4 | 2 | 1 |
5 | 5 | 5 | 5 | 1 | 2 | 1 | 0 |
A | B | A | B | A | B | A | B |
同样的题目换种走法爱丽丝又赢了,因为题目说两个人的状态都很好,所以我猜测是有一种必赢的走法,可以让爱丽丝或者鲍勃在不同的情况下获得胜利,但是我实在是没有想出来,就看了下提示:If the current number is even, we can always subtract a 1 to make it odd. If the current number is odd, we must subtract an odd number to make it even.提示出来可以说就很明显了,就是奇偶数的问题,由上面的例子可以看到,只要有人做到2就赢了,2做因数那上一个肯定也是偶数,所以赢得这场游戏的秘诀就是获得偶数的掌控权,当当前数是奇数的时候,奇数的因数要么是1要么肯定也是奇数,而奇数减奇数得到的就是偶数,当当前数是偶数时,偶数只要减一留给对面的肯定是个奇数,最后一定可以得到2这个答案,所以只要题目是奇数,爱丽丝一定赢不了,只要题目是偶数,爱丽丝一定输不了,这就是赢下这场游戏的秘诀,代码很简单,只有一行:
1 class Solution { 2 public: 3 bool divisorGame(int N) { 4 return N%2==0; 5 } 6 };
返回偶数的判定就可以了,动态规划的思路我没有想出来,就看看了大神的题解,确实比较复杂也比较难以理解:
1 class Solution { 2 public: 3 bool divisorGame(int N) { 4 bool DP[1001]; 5 memset(DP, false, sizeof(DP)); 6 for(int i=1;i<=N;i++){ 7 for(int x=1;x<i;x++){ 8 if(i%x==0&&!DP[i-x]){ 9 DP[i]=true; 10 break; 11 } 12 } 14 } 15 return DP[N]; 16 } 17 };
以上代码出自leetcode:louris,就是循环找当前数的因数然后判断这个数的下一位是赢还是输,赢的话就返回true。