[Leetcode 1025] Dynamic Programming - Divisor Game

1025 - Divisor Game

第一种解法

可以直接考虑这道题是否存在必胜策略:首先考虑最终失败的情况必定是谁的数字变为1谁就失败,不可能是其他情况。

再由题目我们可以思考:

  • 如果输入是一个偶数,那么减掉一个比它小且能整除它的正数,最后得到的可以是一个偶数(减掉的数不为1)也可以是一个奇数(减掉的数是1)
  • 如果输入是一个奇数,那么减掉一个比它小且能整除它的正数,最后得到的一定是一个偶数

通过这一发现,我们可以得到一个结论:在题目已经保证了每一步的选择都是最优的前提下,我只要保证我的对手手里的数字始终是一个奇数,我就必赢。因为奇数无论怎么操作最后给我的都是偶数,而偶数是一定不会输的(只有数字是1时才会输,1是奇数),我只要每次在我拿到的偶数上减1,再把它给我的对手,我的对手手里就始终都是一个奇数,这也保证了我手里始终会是一个偶数,直到我的对手手里的数字变成1,游戏结束。

所以在这种情况下,只要输入是偶数,Alice是必胜的。


class Solution(object):
    def divisorGame(self, N):
        """
        :type N: int
        :rtype: bool
        """
        
        if N % 2 == 0:
            return True
        else:
            return False


if __name__ == '__main__':
    
    solution = Solution()
    print(solution.divisorGame(4))
    
    






第二种解法

第二种解法是采用动态规划的方法。

当当前的数字为n时,状态转移的方式为:

  • 初始化: d p [ 0 ] = T r u e , d p [ 1 ] = F a l s e dp[0]=True, dp[1]=False dp[0]=True,dp[1]=False。(因为当 i = 1 i=1 i=1时要考虑到 n − n / / i = 0 n-n//i=0 nn//i=0,为了使这个值不会对结果产生影响,应该将 d p [ 0 ] dp[0] dp[0]赋值为True)
  • 遍历所有的满足条件 0 < i < n , n % i = 0 0<i<n, \quad n\%i=0 0<i<n,n%i=0 i i i,当其中有任意一种 d p [ n − i ] = F a l s e dp[n-i]=False dp[ni]=False,则 d p [ n ] = T r u e dp[n]=True dp[n]=True。(因为题目已经要求玩家的每一步都是做出的最优操作,所以只要有至少一种能让Bob失败的方案,则Alice必胜)
  • 如果上一步中找不到任何一种使Bob失败的方案,则Alice必败, d p [ n ] = F a l s e dp[n]=False dp[n]=False
import numpy as np


class Solution(object):
    
    def divisorGame(self, N):
        """
        :type N: int
        :rtype: bool
        """
        # 可变类型的值在子函数里面改变,主函数中也会改变
        dp = [-1]*1000
        dp[0] = True
        dp[1] = False
        
        return self.is_alice_win(N, dp)
    
    
    def is_alice_win(self, n, dp):
        
        
        # 终止条件,如果到了某个值时dp值为True或者False
        if dp[n] == True or dp[n] == False:
            return dp[n]
        
        # 循环体,因为题意要求了每次都做的是最优选择,所以只要下面考虑的情况有一次是False,那么说明对方必败,而Alice必胜
        for i in range(1, int(np.sqrt(n))+1):  # 结束条件是n的开方的整数部
            
            if n % i == 0:  # 如果能整除
                ## 当i=1时,n-n//i=0,为了不对结果产生影响,
                if (not self.is_alice_win(n-i, dp)) or (not self.is_alice_win(n-n//i, dp)):
                    dp[n] = True
        
        # 如果所有情况都是Bob必胜,那么当前Alice必败
        if dp[n] == -1:
            dp[n] = False
        
        return dp[n]


if __name__ == '__main__':
    
    solution = Solution()
    print(solution.divisorGame(555))
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值