• 数学石子游戏系列


    877. 石子游戏

    问题描述

    Alice 和 Bob 用几堆石子在做游戏。一共有偶数堆石子,排成一行;每堆都有 正 整数颗石子,数目为 piles[i] 。
    游戏以谁手中的石子最多来决出胜负。石子的 总数 是 奇数 ,所以没有平局。
    Alice 和 Bob 轮流进行,Alice 先开始 。 每回合,玩家从行的 开始 或 结束 处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中 石子最多 的玩家 获胜 。
    假设 Alice 和 Bob 都发挥出最佳水平,当 Alice 赢得比赛时返回 true ,当 Bob 赢得比赛时返回 false 。
    示例 1:
    输入:piles = [5,3,4,5]
    输出:true
    解释:
    Alice 先开始,只能拿前 5 颗或后 5 颗石子 。
    假设他取了前 5 颗,这一行就变成了 [3,4,5] 。
    如果 Bob 拿走前 3 颗,那么剩下的是 [4,5],Alice 拿走后 5 颗赢得 10 分。
    如果 Bob 拿走后 5 颗,那么剩下的是 [3,4],Alice 拿走后 4 颗赢得 9 分。
    这表明,取前 5 颗石子对 Alice 来说是一个胜利的举动,所以返回 true 。
    示例 2:
    输入:piles = [3,7,2,3]
    输出:true

    提示:
    2 <= piles.length <= 500
    piles.length 是 偶数
    1 <= piles[i] <= 500
    sum(piles[i]) 是 奇数

    问题求解

    dp[i][j]: [i:j + 1]先手比后手最多多多少石子。

    class Solution:
        def stoneGame(self, piles: List[int]) -> bool:
            n = len(piles)
    
            @cache
            def dfs(x, y):
                if y - x + 1 == 2:
                    return max(piles[x], piles[y]) - min(piles[x], piles[y])
                return max(piles[x] - dfs(x + 1, y), piles[y] - dfs(x, y - 1))
            
            return dfs(0, n - 1) > 0
    

    1140. 石子游戏 II

    问题描述

    爱丽丝和鲍勃继续他们的石子游戏。许多堆石子 排成一行,每堆都有正整数颗石子 piles[i]。游戏以谁手中的石子最多来决出胜负。
    爱丽丝和鲍勃轮流进行,爱丽丝先开始。最初,M = 1。
    在每个玩家的回合中,该玩家可以拿走剩下的 前 X 堆的所有石子,其中 1 <= X <= 2M。然后,令 M = max(M, X)。
    游戏一直持续到所有石子都被拿走。
    假设爱丽丝和鲍勃都发挥出最佳水平,返回爱丽丝可以得到的最大数量的石头。

    示例 1:
    输入:piles = [2,7,9,4,4]
    输出:10
    解释:如果一开始Alice取了一堆,Bob取了两堆,然后Alice再取两堆。爱丽丝可以得到2 + 4 + 4 = 10堆。如果Alice一开始拿走了两堆,那么Bob可以拿走剩下的三堆。在这种情况下,Alice得到2 + 7 = 9堆。返回10,因为它更大。
    示例 2:
    输入:piles = [1,2,3,4,5,100]
    输出:104
    提示:
    1 <= piles.length <= 100
    1 <= piles[i] <= 104

    问题求解

    class Solution:
        def stoneGameII(self, piles: List[int]) -> int:
            n = len(piles)
    
            @cache
            def dfs(x, m):
                if x >= n: return 0
                if n - x <= 2 * m: return sum(piles[x:])
                res = -float("inf")
                tot = 0
                for i in range(1, 2 * m + 1):
                    tot += piles[x + i - 1]
                    res = max(res, tot - dfs(x + i, max(m, i)))
                return res
            
            diff = dfs(0, 1)
    
            return (sum(piles) + diff) // 2
    

    1406. 石子游戏 III

    问题描述

    Alice 和 Bob 用几堆石子在做游戏。几堆石子排成一行,每堆石子都对应一个得分,由数组 stoneValue 给出。
    Alice 和 Bob 轮流取石子,Alice 总是先开始。在每个玩家的回合中,该玩家可以拿走剩下石子中的的前 1、2 或 3 堆石子 。比赛一直持续到所有石头都被拿走。
    每个玩家的最终得分为他所拿到的每堆石子的对应得分之和。每个玩家的初始分数都是 0 。比赛的目标是决出最高分,得分最高的选手将会赢得比赛,比赛也可能会出现平局。
    假设 Alice 和 Bob 都采取 最优策略 。如果 Alice 赢了就返回 "Alice" ,Bob 赢了就返回 "Bob",平局(分数相同)返回 "Tie" 。

    示例 1:
    输入:values = [1,2,3,7]
    输出:"Bob"
    解释:Alice 总是会输,她的最佳选择是拿走前三堆,得分变成 6 。但是 Bob 的得分为 7,Bob 获胜。
    示例 2:
    输入:values = [1,2,3,-9]
    输出:"Alice"
    解释:Alice 要想获胜就必须在第一个回合拿走前三堆石子,给 Bob 留下负分。
    如果 Alice 只拿走第一堆,那么她的得分为 1,接下来 Bob 拿走第二、三堆,得分为 5 。之后 Alice 只能拿到分数 -9 的石子堆,输掉比赛。
    如果 Alice 拿走前两堆,那么她的得分为 3,接下来 Bob 拿走第三堆,得分为 3 。之后 Alice 只能拿到分数 -9 的石子堆,同样会输掉比赛。
    注意,他们都应该采取 最优策略 ,所以在这里 Alice 将选择能够使她获胜的方案。
    示例 3:
    输入:values = [1,2,3,6]
    输出:"Tie"
    解释:Alice 无法赢得比赛。如果她决定选择前三堆,她可以以平局结束比赛,否则她就会输。
    示例 4:
    输入:values = [1,2,3,-1,-2,-3,7]
    输出:"Alice"
    示例 5:
    输入:values = [-1,-2,-3]
    输出:"Tie"

    提示:
    1 <= values.length <= 50000
    -1000 <= values[i] <= 1000

    问题求解

    class Solution:
        def stoneGameIII(self, stoneValue: List[int]) -> str:
            n = len(stoneValue)
    
            @cache
            def dfs(x):
                if x >= n: return 0
                res = -float("inf")
                res = max(res, stoneValue[x] - dfs(x + 1))
                if x + 1 < n:
                    res = max(res, stoneValue[x] + stoneValue[x + 1] - dfs(x + 2))
                if x + 2 < n:
                    res = max(res, stoneValue[x] + stoneValue[x + 1] + stoneValue[x + 2] - dfs(x + 3))
                return res
            
            diff = dfs(0)
    
            if diff > 0:
                return "Alice"
            elif diff == 0:
                return "Tie"
            else:
                return "Bob"
    

    1510. 石子游戏 IV

    问题描述

    Alice 和 Bob 两个人轮流玩一个游戏,Alice 先手。
    一开始,有 n 个石子堆在一起。每个人轮流操作,正在操作的玩家可以从石子堆里拿走 任意 非零 平方数 个石子。
    如果石子堆里没有石子了,则无法操作的玩家输掉游戏。
    给你正整数 n ,且已知两个人都采取最优策略。如果 Alice 会赢得比赛,那么返回 True ,否则返回 False 。

    示例 1:
    输入:n = 1
    输出:true
    解释:Alice 拿走 1 个石子并赢得胜利,因为 Bob 无法进行任何操作。
    示例 2:
    输入:n = 2
    输出:false
    解释:Alice 只能拿走 1 个石子,然后 Bob 拿走最后一个石子并赢得胜利(2 -> 1 -> 0)。
    示例 3:
    输入:n = 4
    输出:true
    解释:n 已经是一个平方数,Alice 可以一次全拿掉 4 个石子并赢得胜利(4 -> 0)。
    示例 4:
    输入:n = 7
    输出:false
    解释:当 Bob 采取最优策略时,Alice 无法赢得比赛。
    如果 Alice 一开始拿走 4 个石子, Bob 会拿走 1 个石子,然后 Alice 只能拿走 1 个石子,Bob 拿走最后一个石子并赢得胜利(7 -> 3 -> 2 -> 1 -> 0)。
    如果 Alice 一开始拿走 1 个石子, Bob 会拿走 4 个石子,然后 Alice 只能拿走 1 个石子,Bob 拿走最后一个石子并赢得胜利(7 -> 6 -> 2 -> 1 -> 0)。
    示例 5:
    输入:n = 17
    输出:false
    解释:如果 Bob 采取最优策略,Alice 无法赢得胜利。

    提示:
    1 <= n <= 10^5

    问题求解

    class Solution:
        @cache
        def winnerSquareGame(self, n: int) -> bool:
            if n == 0: return False
            for i in range(1, n + 1):
                if n - i * i < 0: break
                if not self.winnerSquareGame(n - i * i): return True
            return False
    

    1563. 石子游戏 V

    问题描述

    几块石子 排成一行 ,每块石子都有一个关联值,关联值为整数,由数组 stoneValue 给出。
    游戏中的每一轮:Alice 会将这行石子分成两个 非空行(即,左侧行和右侧行);Bob 负责计算每一行的值,即此行中所有石子的值的总和。Bob 会丢弃值最大的行,Alice 的得分为剩下那行的值(每轮累加)。如果两行的值相等,Bob 让 Alice 决定丢弃哪一行。下一轮从剩下的那一行开始。
    只 剩下一块石子 时,游戏结束。Alice 的分数最初为 0 。
    返回 Alice 能够获得的最大分数 。

    示例 1:
    输入:stoneValue = [6,2,3,4,5,5]
    输出:18
    解释:在第一轮中,Alice 将行划分为 [6,2,3],[4,5,5] 。左行的值是 11 ,右行的值是 14 。Bob 丢弃了右行,Alice 的分数现在是 11 。
    在第二轮中,Alice 将行分成 [6],[2,3] 。这一次 Bob 扔掉了左行,Alice 的分数变成了 16(11 + 5)。
    最后一轮 Alice 只能将行分成 [2],[3] 。Bob 扔掉右行,Alice 的分数现在是 18(16 + 2)。游戏结束,因为这行只剩下一块石头了。
    示例 2:
    输入:stoneValue = [7,7,7,7,7,7,7]
    输出:28
    示例 3:
    输入:stoneValue = [4]
    输出:0

    提示:
    1 <= stoneValue.length <= 500
    1 <= stoneValue[i] <= 10^6

    问题求解

    这里只给出O(n ^ 3)的解法,可以通过二分搜索将时间复杂度进一步降低,但有点超纲,不做深究。

    class Solution:
        def stoneGameV(self, stoneValue: List[int]) -> int:
            n = len(stoneValue)
            presum = [0] * n
            presum[0] = stoneValue[0]
            for i in range(1, n):
                presum[i] = presum[i - 1] + stoneValue[i]
    
            @cache
            def dfs(x, y):
                if x == y: return 0
                res = 0
                for i in range(x, y):
                    l = presum[i] - presum[x] + stoneValue[x]
                    r = presum[y] - presum[i]
                    if l > r: res = max(res, r + dfs(i + 1, y))
                    elif l == r: 
                        res = max(res, l + dfs(x, i), r + dfs(i + 1, y))
                    else: res = max(res, l + dfs(x, i))
                return res
            
            return dfs(0, n - 1)
    
  • 相关阅读:
    中科大算法分析与设计分布式算法复习知识点
    记录一些实用网站
    《TensorFlow机器学习项目实战》pdf及源码
    DevC++连接MySQL可用详细教程
    【转】MySQL合理使用索引
    【原】基于Feign 重写自定义编码器
    【原】logback实现按业务输出到对应日志文件
    【原】MDC日志链路设计
    关于看源码的心得体会
    【原】基于Spring实现策略模式
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/16674241.html
Copyright © 2020-2023  润新知