【问题标题】:Generalised Two-Egg Puzzle广义的两蛋拼图
【发布时间】:2012-04-27 23:24:52
【问题描述】:

这是问题描述:

假设我们想知道 N 层建筑中的哪些楼层可以安全地掉落鸡蛋,哪些楼层会导致鸡蛋在落地时破裂。我们做几个假设: 跌倒后幸存下来的鸡蛋可以再次使用。

  • 必须丢弃破损的鸡蛋。
  • 跌倒对所有鸡蛋的影响都是一样的。
  • 如果鸡蛋在掉落时破裂,那么如果从更高的窗户掉落,它也会破裂。
  • 如果一个鸡蛋在坠落中幸存下来,那么它会在较短的坠落中幸存下来。
  • 不排除一楼窗户打碎鸡蛋,也不排除N楼窗户不打碎鸡蛋。

给定一栋 N 层的建筑物和 d 个鸡蛋的供应,找到最小化(在最坏的情况下)确定起床所需的实验下降次数的策略。


我已经看到并解决了 2 个鸡蛋的这个问题,其中 N=100 的答案是 14。 我试图使用 DP 从 wiki 理解通用解决方案,但无法理解他们想要做什么。请告诉他们如何到达 DP 以及它是如何工作的?

编辑:

this文章中给出的可以用d滴和e鸡蛋测试的最高楼层的Recurrence如下:

f[d,e] = f[d-1,e] + f[d-1,e-1] + 1

循环很好,但我无法理解它是如何得出的?

这个解释对我来说不是很清楚......我只是希望有人用更清楚的语言向我解释这种复发。

【问题讨论】:

  • 您是否缺少一些上下文? “他们”是谁?你说的维基是什么?
  • 不查看您链接的文档,该递归表达式看起来与计算组合的方式惊人地相似。
  • Wiki 是维基百科页面en.wikipedia.org/wiki/Dynamic_programming#Egg_dropping_puzzle 上的谜题的解释,“他们”被用作网络上针对这个特定问题的资源的总称。

标签: algorithm puzzle dynamic-programming


【解决方案1】:

(1) 考虑第一滴打碎鸡蛋的情况。 然后当且仅当它至多为 f[d-1, e-1] 时,您可以确定打破地板。因此,你不能从高于 f[d-1, e-1] + 1 开始(当然也不应该开始低于)。

(2) 如果你的第一滴没有打破鸡蛋,你是在 f[d-1, e] 的情况下,从你的第一滴的地板 + 1 开始,而不是 1 楼。

所以,你能做的最好的事情是开始在 f[d-1, e-1] + 1 楼下蛋(因为 (1)),你可以起床到f[d-1, e] 层比那个高(因为(2))。那是

f[d, e] = f[d-1, e-1] + 1 + f[d-1, e]

【讨论】:

  • thnx !...我只是错过了我必须计算的最高可达楼层
  • 我理解上面的答案,但我想知道是否存在分析解决方案。在2个鸡蛋的情况下,我们可以使用三角数的总和,但是我还没有找到任何关于鸡蛋数量超过2的解析解的文献。难道不能解析解决这个问题吗?
  • @Prof 稍微搜索一下就可以找到一个声称有公式的类似问题的答案:link
  • @Prof:公式其实很漂亮。其中 f[d,e] 是由和 (d,1) + (d,2) + ... + (d,e) 给出的多项式,其中 (n.k) 是二项式系数。
【解决方案2】:

此处提供基于动态编程的解决方案 - http://algohub.blogspot.in/2014/05/egg-drop-puzzle.html

我相信这是不言自明的..如果有任何不清楚的地方,请随时询问..很乐意解释

【讨论】:

    【解决方案3】:

    Wiki Egg Dropping puzzle我们知道状态转移方程是:

    W(n,k) = 1 + min{ max(W(n − 1, x − 1), W(n,k − x)) } , x = 1, 2, ..., k

    W(n,1)=1, W(1,k)=k

    n = 可用测试鸡蛋的数量

    k = 待测试的(连续)楼层数

    以下是我的理解。

    我们有k 楼层,n 鸡蛋,假设我们使用鸡蛋在x 楼层进行测试。只有两种可能的结果:

    1. 它坏了,所以问题递归到:x-1楼层,n-1鸡蛋,这反映到W(n-1,x-1)
    2. 它没有中断,所以问题递归到:k-x楼层,n鸡蛋,反映到W(n,k-x)

    由于问题需要最坏的情况,我们必须选择更大的一个以确保最坏的情况有效,这就是为什么我们在W(n-1,x-1)W(n,k-x) 之间添加一个最大值。

    另外,由于我们只是假设在x楼测试,x可以从1k,在这种情况下,我们肯定需要选择最小值以确保最小实验下降来找出N,这就是为什么我们在 {max(W(n − 1, x − 1), W(n,k − x)): x = 1, 2, ..., k} 之间添加一个分钟

    最后,由于我们使用了1 drop in x floor,所以等式必须添加1,这反映到等式的第一部分。

    希望能解决你的难题 :-)

    【讨论】:

      【解决方案4】:

      这个问题可以通过以下 3 种方法来解决(据我所知):

      1. 动态编程
      2. 使用二叉搜索树的解决方案
      3. 通过获得可以测试或覆盖给定数量的鸡蛋和给定的滴数的最大楼层数的直接数学公式来解决

      让我先定义一些用于之后分析的符号:

      e = number of eggs
      f = number of floors in building
      n = number of egg drops 
      Fmax(e, n) = maximum number of floors that can be tested or covered with e eggs and n drops
      

      动态规划方法的关键在于以下Fmax的递归公式:

      Fmax(e, n) = 1 + Fmax(e-1, n-1) + fmax(e, n-1)
      

      而获得Fmax的直接数学公式的关键在于以下Fmax的递归公式:

      Fmax(e, n) = { ∑Fmax(e-1,i) for i = 1 to n } - Fmax(e-1, n) + n 
      

      使用二叉搜索树 (BST) 的替代解决方案也可以解决此问题。为了便于分析,我们画出BST,稍作修改如下:

      1.    If egg breaks then child node is drawn on left down side
      2.    If egg does not break then child node is drawn straight down side
      

      如果我们用上述表示形式绘制 BST,那么 BST 的宽度代表鸡蛋的数量。

      任何具有f个节点的BST,用上述表示形式绘制并受到BST

      因此得到最优解相当于得到BST中节点的排列方式,其高度受约束为:BST的宽度

      有关以上 3 种方法的更多详细信息,请查看我的博客:3 approaches for solving generalized egg drop problem

      【讨论】:

        【解决方案5】:

        这个问题不在于应该从哪个地板上掉下鸡蛋,而是要尽量减少掉下的次数。

        • 假设,那么我们有 n 个鸡蛋和 k 个楼层,
        • 基础案例:
          • 当 floor 为 1 时,MinNoOfDrops(n, 1)=1
          • 当 egg 为 1 时,MinNoOfDrops(1, k)=k
        • 通用解决方案:
        • MinNoOfDrops(n, k) = 1 + min{ max(MinNoOfDrops(n - 1, x - 1),
          MinNoOfDrops(n,k − x)) } , x = 1, 2, ..., k

        动态规划算法:

        • 创建 (totalEggs + 1) X (totalFloors + 1) 的 dp 表

        • 基本情况:当鸡蛋为 0 或 1 时,设置为第 i 层,table[0][i] = 0;和表[1][i] = i

        • 基本情况:地板为 0 或 1,然后设置为鸡蛋 j,table[j][0] = 0 和表[j][1] = 1

        • 将鸡蛋 i 从 2 迭代到 total_eggs

          • 将层 j 从 2 迭代到 total_floors
            • 设置表[i][j] = INFINITY
            • 从 1 到 j 迭代 k 层
            • 设置 maxDrop = 1 + max(table[i-1][k-1], table[i][j-k])
            • 如果 table[i][j] > maxDrop 那么
              • 设置表[i][j] = maxDrop

        public class EggDroppingPuzzle {
        
            /** Not efficient  **/
            public static int solveByRecursion(int totalEggs, int totalFloors) {
        
                /** Base Case: When no floor **/
                if (totalFloors == 0) {
                    return 0;
                }
        
                /** Base case: When only one floor **/
                if (totalFloors == 1) {
                    return 1;
                }
        
                /** Base case: When only one eggs, then we have to try it from all floors **/
                if (totalEggs == 1) {
                    return totalFloors;
                }
        
                int minimumDrops = Integer.MAX_VALUE;
                /** Now drop a egg from floor 1 to totalFloors **/
                for (int k = 1; k <= totalFloors; k++) {
        
                    /** When an egg breaks at kth floor **/
                    int totalDropWhenEggBreaks = solveByRecursion(totalEggs - 1, k - 1);
        
                    /** When egg doesn't break at kth floor **/
                    int totalDropWhenEggNotBreaks = solveByRecursion(totalEggs, totalFloors - k);
        
                    /** Worst between above conditions **/
                    int maxDrop = Math.max(totalDropWhenEggBreaks, totalDropWhenEggNotBreaks);
        
        
                    /** Minimum drops for all floors **/
                    if (minimumDrops > maxDrop) {
                        minimumDrops = maxDrop;
                    }
                }
        
                return minimumDrops + 1;
            }
        
            public static int solveByByDP(int totalEggs, int totalFloors) {
                int[][] table = new int[totalEggs + 1][totalFloors + 1];
        
                /** Base Case: When egg is zero or one **/
                for (int i = 0; i < totalFloors + 1; i++) {
                    table[0][i] = 0;
                    table[1][i] = i;
                }
        
                /** Base case: Floor is zero or one **/
                for (int j = 0; j < totalEggs + 1; j++) {
                    table[j][0] = 0;
                    table[j][1] = 1;
                }
        
                /** For floor more than 1 and eggs are also more than 1 **/
                for (int i = 2; i < totalEggs + 1; i++) {
                    for (int j = 2; j < totalFloors + 1; j++) {
        
                        table[i][j] = Integer.MAX_VALUE;
                        for (int k = 1; k <= j; k++) {
        
                            /** When an egg breaks at kth floor **/
                            int totalDropWhenEggBreaks = table[i - 1][k - 1];
        
                            /** When egg doesn't break at kth floor **/
                            int totalDropWhenEggNotBreaks = table[i][j - k];
        
                            /** Worst between above conditions **/
                            int maxDrop = 1 + Math.max(totalDropWhenEggBreaks, totalDropWhenEggNotBreaks);
        
                            /** Minimum drops for all floors **/
                            if (maxDrop < table[i][j]) {
                                table[i][j] = maxDrop;
                            }
                        }
                    }
                }
        
                return table[totalEggs][totalFloors];
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-03-25
          • 1970-01-01
          • 2015-02-23
          • 1970-01-01
          • 2017-02-28
          • 1970-01-01
          • 1970-01-01
          • 2020-05-18
          相关资源
          最近更新 更多