【问题标题】:"Bricks Game" from HackerRankHackerRank 的“砖块游戏”
【发布时间】:2016-10-16 02:15:52
【问题描述】:

我一直在尝试解决来自 HackerRank 的动态编程部分的this 问题。我阅读了编辑解决方案并理解了它。但是,它直接跳转到动态编程方法。我想知道这个问题的蛮力方法是什么。

描述:您和您的朋友决定使用由 N 个积木组成的堆栈来玩游戏。在这个游戏中,您可以选择从顶部移除 1、2 或 3 块积木,然后将蚀刻在移除积木上的数字添加到您的分数中。你必须玩,以便获得最大可能的分数。假设您的朋友也将发挥最佳效果,而您迈出了第一步。

我最初的想法是枚举所有可能的 1,2,3 长度的砖块组合,从栈顶开始一直到栈底。让我们将此枚举称为 S。然后,在 S 中为所有 x(您的分数)和 y(对手的分数)找到所有可能的 (x,y),其中 x != y。最后遍历所有这些对并计算您的最高分数(例如 x 的最大总和)。

【问题讨论】:

    标签: algorithm dynamic-programming


    【解决方案1】:

    好吧,这里动态规划只是一种避免多次计算相同子问题的方法(其他可能性是使用memoization)。

    解决这类问题的一般思路如下:

    AB 成为玩家,A 先行动。此外,让f(n,p) 表示玩家p 的堆栈大小为n 的最大得分,即p 的堆栈大小为n

    思路很简单,A想最大化f(n,A)。请注意,A 从输入中给出的初始位置开始最多可以进行 3 次不同的移动:

    • 拿 1 块砖
    • 拿2块砖
    • 拿 3 块砖

    此外,如果A 得分X,那么B 得分S(n) - X,其中S(n)n 底砖得分的总和。

    基于这些观察,我们可以这样写:

    f(n,A) = max(S(n)-f(n-1,B), S(n)-f(n-2,B), S(n)-f(n-3,B)).

    换句话说,他的最佳结果是这些可用动作中的最大值(请注意,如果筹码很小,可用的动作可能少于 3 个)。

    现在,动态规划只是用来避免多次计算 f(n,p) 的相同值 - 如果你扩展 f(n,A) 的公式,你会发现当 n 增长时它们会越来越多地出现在那里.因此,为了优化解决方案,f 的已计算值存储在内存中,并在需要时以恒定时间返回。

    【讨论】:

    • 但是我们不想要中间状态的最高分。相反,我们希望得到最终的最高分。例如,考虑 arr = [0,1,2,1,999],解决方案应该是 score(A) = 999 和 score(B) = 4,因为玩家 A 应该拿走第一块和最后一块砖。那么对于从1到4的每一个i,A的得分都小于B的得分。
    • @lenhhoxung 我给出的解决方案使最终得分最大化,看看f(n,A)的公式和定义
    • 感谢您的回复。我是 DP 的新手,所以不确定我是否理解得很好。在这里,您定义了“让 f(n,p) 表示玩家 p 的最大分数,堆栈大小为 n”。那么玩家应该每一步都有最高分(即 n 变化)?还是我很困惑?
    【解决方案2】:

    看看Minimax algorithm。您通常会在其中构建一个完整的树,其中一个级别将为您生成所有可能的移动,下一个级别将为您的对手生成所有可能的移动,用于您在前一个级别生成的每个状态并继续。在每个级别中,您必须将可能的损失降到最低,以应对下一个级别的最坏情况。这里生成了所有可能的移动/分支,所以它几乎是蛮力的。

    显然你可以在 Minimax 树上应用剪枝,但你应该先看看暴力法。

    【讨论】:

      猜你喜欢
      • 2018-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多