除数博弈

 1. 题目

这道题是Leetcode中动态规划类型的一道题,题目难度为简单。

题目链接:除数博弈

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

最初,黑板上有一个数字 n 。在每个玩家的回合,玩家需要执行以下操作:

  • 选出任一 x,满足 0 < x < n 且 n % x == 0 。
  • 用 n - x 替换黑板上的数字 n 。

如果玩家无法执行这些操作,就会输掉游戏。

只有在爱丽丝在游戏中取得胜利时才返回 true 。假设两个玩家都以最佳状态参与游戏。

2.思路

由于我们是为了训练动态规划的解题思路,因此我们不考虑其它的方法。在这道题中,如果数字为1的话,它没有任何操作,因此Alice必定输。

dp数组初始化

那么我们可以定义一个dp数组,并初始化数组元素为[0,0],这里定义两个是因为游戏是从1开始,为了方便下标计算才定义两个。

状态转移表达式

接着,我们需要找到它们的状态转移表达式,假设a + b = c,如果dp[a]和dp[b]都为1,那么我们不妨大胆猜测dp[c]=1。为啥呢?因为如果alice对于a和b都能赢,那么对于c,他可以分两步来减数。

那么我们初步的状态表达式为:

dp[i] = dp[i-a] & dp[a]

那还有其它的情况吗?有,对于动态规划的题目来说,前面几个数是最特殊的,对于数字1和2,我们可以很容易发现我们前面的状态转移有问题,因为2 = 1 + 1,而dp[1]=0,那么dp[2]如果根据前面的表达式就是有问题的。对于这个情况,我们猜测:如果a + b = c,同时dp[a]和dp[b]相等,那么dp[c]就为1。这个猜测是包含前面的表达式,同时也包含刚才的特殊情况。

因此改正的状态表达式为:

dp[i] = ! dp[i-a] ^ dp[a]

代码实现

有了刚才的状态表达式,那我们用代码如何实现呢?我们该如何考虑多种情况呢?因为一个数不止两个加数(想了好久才想到,大学白读了),因此我们需要用双指针来寻找这些子状态,然后进行判断,如果存在子状态符合上述情况则当前dp[i]为1。

3.代码

class Solution:
    def divisorGame(self, n: int) -> bool:
        dp = [0,0]
        for i in range(2,n+1):
            left,right = 1,i-1
            isT = False
            while left <= right:
                if dp[left] ^ dp[right] == 0:
                    dp.append(1)
                    isT = True
                    break
                left += 1
                right -= 1
            if not isT:
                dp.append(0)
        return dp[-1] == 1
                
            
            
                    

            
                

你可能感兴趣的:(算法解析,算法,数据结构,python)