【问题标题】:Understanding solution to finding optimal strategy for game involving picking pots of gold了解为涉及采摘金罐的游戏寻找最佳策略的解决方案
【发布时间】:2014-03-05 10:39:05
【问题描述】:

我无法理解this question on CareerCup 解决方案背后的原因。

金罐游戏:A 和 B 两个玩家。安排了金罐 在一条线上,每个都包含一些金币(玩家可以看到如何 每个金罐里都有很多硬币——完美的信息)。他们得到 交替轮流,玩家可以从其中一个中选择一个底池 线的末端。获胜者是拥有更高数字的玩家 最后的硬币。目标是“最大化” A 收集的硬币,假设 B 也玩得最好。 A 开始 游戏。

我们的想法是找到一个最优策略,让 A 知道 B也打得很好。你会怎么做?

最后我被要求编写这个策略!

这是来自 Google 采访的问题。

建议的解决方案是:

function max_coin( int *coin, int start, int end ):
    if start > end:
        return 0

    // I DON'T UNDERSTAND THESE NEXT TWO LINES
    int a = coin[start] + min(max_coin(coin, start+2, end), max_coin(coin, start+1, end-1))
    int b = coin[end] + min(max_coin(coin, start+1,end-1), max_coin(coin, start, end-2))

    return max(a,b)

有两个具体部分我不明白:

  1. 在第一行中,为什么我们使用范围 [start + 2, end] 和 [start + 1, end - 1]?它总是遗漏一个硬币罐。不应该是 [start + 1, end] 因为我们取出了起始硬币罐吗?
  2. 在第一行中,为什么我们取两个结果中的最小值而不是最大值?
  3. 因为我对为什么这两条线取最小值以及为什么我们选择这些特定范围感到困惑,所以我不确定ab 究竟代表什么?

【问题讨论】:

  • 你确定是java吗?
  • 你必须递归地解决每个子任务。

标签: algorithm


【解决方案1】:

首先ab分别代表播放start(分别为end)时的最大增益。

所以让我们解释一下这一行:

int a = coin[start] + min(max_coin(coin, start+2, end), max_coin(coin, start+1, end-1))

如果我玩start,我将立即获得coin[start]。另一个玩家现在必须在start+1end 之间玩。他打球是为了最大化他的收益。然而,由于硬币的数量是固定的,这相当于减少我的数量。请注意

  • 如果他玩start+1,我将获得max_coin(coin, start+2, end)
  • 如果他玩end 将获得max_coin(coin, start+1, end-1)

既然他试图最小化我的收益,我将获得这两者中的最小值。

同样的推理也适用于我玩end的另一行。

注意:这是一个糟糕的递归实现。首先max_coin(coin, start+1, end-1) 被计算了两次。即使你解决了这个问题,你最终也会计算出很多时间较短的情况。这与您尝试使用递归计算斐波那契数时发生的情况非常相似。最好使用记忆化或动态编程。

【讨论】:

  • 你能解释一下如何使用动态规划解决上述问题。
  • @coder_15 您只需将中间值存储在表或类似的东西中以避免重新计算它们。
  • 加 1 以获得更好的解释
【解决方案2】:

ab这里分别代表A可以通过选择起始锅或结束锅获得的最大值。

我们实际上是在尝试最大化A-B,但是由于B = TotalGold - A,我们正在尝试最大化2A - TotalGold,并且由于TotalGold 是恒定的,我们正在尝试最大化2A,即与A 相同,因此我们完全忽略B 的选择值,只使用A

递归调用中更新的参数还包括B 选择 - 所以coin[start] 代表A 选择开始,然后B 从开始选择下一个,所以它是start+2。对于下一个调用,B 从末尾开始选择,所以它是 start+1end-1。其余的也一样。

我们选择min,因为B 会尝试最大化它自己的利润,所以它会选择最小化A 的利润的选择。

但实际上我想说这个解决方案有点缺乏,因为它只返回一个值,而不是“最佳策略”,在我看来,这将是一系列动作。而且它也没有考虑到A不能获胜的可能性,在这种情况下,人们可能想输出一条消息说这是不可能的,但这确实是需要与面试官澄清的事情。

【讨论】:

    【解决方案3】:

    让我以相反的顺序回答你的观点,不知何故,这样似乎更有意义。

    3 - a 和 b 代表第一个玩家将获得的硬币数量,当他/她分别选择第一个或最后一个底池时

    2 - 我们取最小值,因为这是第二个玩家的选择 - 他/她将采取行动以最小化第一个玩家将获得的硬币数量

    1 - 第一行展示了场景 - 如果第一个玩家拿到了第一个底池,那么第二个玩家会怎么做?如果他/她再次拿走第一个底池,它将离开(开始+2,结束)。如果他/她拿走了最后一个底池,它将离开(start+1,end-1)

    【讨论】:

      【解决方案4】:

      假设你在你的回合中获得的是x,而你在所有后续回合中获得的是y。这两个值都代表x+y,其中a 假设你从前面拿下一个底池(x=coin[start]),b 假设你从后面拿下一个底池(x=coin[end])。

      现在你如何计算y

      在你选择之后,对手将使用相同的最优策略(因此递归跟注)来最大化他的利润,而你将在转牌圈获得较小的利润。这就是为什么你的y=min(best_strategy_front(), best_strategy_end())——你的价值是剩下的两个选择中较小的一个,因为对手会选择更大的。

      在您做出选择后,索引仅指示剩余的序列减去正面和背面的一个锅。

      【讨论】:

        【解决方案5】:

        我也有一分钱。我已经详细解释了步骤。

        public class Problem08 {
          static int dp[][];
        
          public static int optimalGameStrategy(int arr[], int i, int j) {
            //If one single element then choose that.
            if(i == j) return arr[i];
        
            //If only two elements then choose the max.
            if (i + 1 == j ) return Math.max(arr[i], arr[j]);
        
            //If the result is already computed, then return that.
            if(dp[i][j] != -1) return dp[i][j];
        
            /**
             * If I choose i, then the array length will shrink to i+1 to j.
             * The next move is of the opponent. And whatever he choose, I would want the result to be
             * minimum. If he choose j, then array will shrink to i+1, j-1. But if also choose i then
             * array will shrink to i+2,j. Whatever he choose, I want the result to be min, hence I take
             * the minimum of his two choices.
             *
             * Similarly for a case, when I choose j.
             *
             * I will eventually take the maximum of both of my case. :)
             */
            int iChooseI = arr[i] + Math.min(optimalGameStrategy(arr, i+1, j-1),
                optimalGameStrategy(arr, i+2, j));
            int iChooseJ = arr[j] + Math.min(optimalGameStrategy(arr, i+1, j-1),
                optimalGameStrategy(arr, i, j-2));
            int res = Math.max(iChooseI, iChooseJ );
            dp[i][j] = res;
            return res;
          }
        
        
          public static void main(String[] args) {
            int[] arr = new int[]{5,3,7,10};
            dp = new int[arr.length][arr.length];
            for(int i=0; i < arr.length; i++) {
              for(int j=0; j < arr.length; j++) {
                dp[i][j] = -1;
              }
            }
            System.out.println( " Nas: " + optimalGameStrategy(arr, 0, arr.length-1));
          }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-11
          • 1970-01-01
          • 1970-01-01
          • 2014-12-12
          • 1970-01-01
          • 2017-03-27
          • 2012-04-23
          • 1970-01-01
          相关资源
          最近更新 更多