• 395. 硬币排成线 II


    395. 硬币排成线 II

    中文English

    有 n 个不同价值的硬币排成一条线。两个参赛者轮流从 左边 依次拿走 1 或 2 个硬币,直到没有硬币为止。计算两个人分别拿到的硬币总价值,价值高的人获胜。

    请判定 先手玩家 必胜还是必败?

    若必胜, 返回 true, 否则返回 false.

    样例

    样例 1:

    输入: [1, 2, 2]
    输出: true
    解释: 先手玩家直接拿走两颗硬币即可.
    

    样例 2:

    输入: [1, 2, 4]
    输出: false
    解释: 无论先手拿一个还是两个, 后手可以拿完, 然后总价值更高.
    输入测试数据 (每行一个参数)如何理解测试数据?

     解法一:动态规划

    dp[i]代表的是倒数n-i个,逆着算,例如dp[length - 2] = values[length - 2] + values[length - 1] ,表示的是i到length - 1可以拿到的最大值

    class Solution:
        """
        @param values: a vector of integers
        @return: a boolean which equals to true if the first player will win
        """
        def firstWillWin(self, values):
            # write your code here
            #动态规划
            #如果是len(values)<= 3的情况,则直接给出答案
            #如果是len(valeus) > 3的情况,分情况,要么先手拿一个,要么拿两个
            
            length = len(values)
            if (length <= 2): return True 
            
            dp = [0 for _ in range(length + 1)]
            total = 0 
            
            #如果是<=3的话
            #如果是只拿最后一个的话,先手必拿
            dp[length - 1] = values[length - 1]
            #如果是剩余最后两个的话,先手也必拿
            dp[length - 2] = values[length - 1] + values[length - 2]
            #如果是剩余三个的话,那么先手最优策略是拿前两个,最后一个留给后手
            dp[length - 3] = values[length - 2] + values[length - 3]
            
            total = sum(values[length - 3:])
            #如果是大于3的话,分情况考虑
            for i in range(length - 4, -1, -1):
                total += values[i]
                
                #先手要么拿一个,要么拿两个,后手也是最优策略,所以后手也尽可能的多拿,min(dp[i + 2], dp[i + 3])
                dp[i] = max(values[i] + min(dp[i + 2], dp[i + 3]), values[i] + values[i + 1] + min(dp[i + 3], dp[i + 4]))
            
            #最后比较两者大小,肯定是先手拿,也就是第一个
            return dp[0] > total - dp[0]
                

    394. 硬币排成线

    中文English

    有 n 个硬币排成一条线。两个参赛者轮流从右边依次拿走 1 或 2 个硬币,直到没有硬币为止。拿到最后一枚硬币的人获胜。

    请判定 先手玩家 必胜还是必败?

    若必胜, 返回 true, 否则返回 false.

    样例

    样例 1:

    输入: 1
    输出: true
    

    样例 2:

    输入: 4
    输出: true
    解释: 
    先手玩家第一轮拿走一个硬币, 此时还剩三个.
    这时无论后手玩家拿一个还是两个, 下一次先手玩家都可以把剩下的硬币拿完.
    

    挑战

    O(1) 时间复杂度且O(1) 存储。

    输入测试数据 (每行一个参数)如何理解测试数据?

     解法:动态规划

    class Solution:
        """
        @param n: An integer
        @return: A boolean which equals to true if the first player will win
        """
        def firstWillWin(self, n):
            # write your code here
            #当前必胜和必败由前面两个决定
            #只考虑先手,and表示的是后手的最优策略,只要有前面先手有一个为False,那么后手一定是True
            #dp[i] = dp[i - 2] and dp[i - 3] or dp[i - 3] and dp[i - 4]
            #当前先手 = 取一个后手的最优策略 取两个后手的最优策略(所以中间是and,表示,只要之前先手一个为False,此时后手采取最优策略,一定为True)
            if not n: return False
            if n <= 2: return True 
            
            dp = [False for _ in range(n + 1)]
    
            #前面三个的话,是固定
            dp[1] = True 
            dp[2] = True
            dp[3] = False 
            
            for i in range(4, n + 1):
                dp[i] = (dp[i - 2] and dp[i - 3]) or (dp[i - 3] and dp[i - 4])
            
            return dp[n]
                
  • 相关阅读:
    luogu P1486 [NOI2004]郁闷的出纳员
    Luogu P1894 [USACO4.2]The Perfect Stall
    关于中间6个月停更通知
    Luogu P1381油滴扩展
    没有上司的舞会(题解)
    幂的模运算(题解)
    闭合区域面积统计(题解)
    字符序列(题解)
    最大连续和(题解)
    排列问题
  • 原文地址:https://www.cnblogs.com/yunxintryyoubest/p/13337665.html
Copyright © 2020-2023  润新知