广义双蛋拼图

时间:2012-04-16 15:48:24

标签: algorithm puzzle dynamic-programming

以下是问题描述:

假设我们想知道N层建筑中的哪些故事可以安全地从中掉落鸡蛋,哪些会导致鸡蛋在着陆时破裂。我们做了一些假设: 可以再次使用在摔倒后存活的鸡蛋。

  • 必须丢弃破蛋。
  • 所有鸡蛋的跌倒效果都相同。
  • 如果鸡蛋在掉落时断裂,那么如果从较高的窗口掉落则会破裂。
  • 如果一个鸡蛋在摔倒后存活下来,那么它会在较短的摔倒后存活下来。
  • 不排除一楼的窗户打破鸡蛋,也不排除N楼的窗户不会打破鸡蛋。

考虑到N层建筑和d蛋的供应,找到了最小化(在最坏的情况下)确定断裂所需的实验滴数的策略。


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

编辑:

this条款中给出的可用d滴和e蛋测试的最高层的复发如下:

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

复发很好,但我无法理解它是如何衍生的?

我的解释并不清楚......我只是希望有人用更清晰的话语向我解释这种情况。

5 个答案:

答案 0 :(得分:10)

(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]

答案 1 :(得分:9)

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)
  3. 由于问题需要最坏的情况,我们必须选择较大的问题以确保最坏的情况有效,这就是我们在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}之间添加分钟

    最后,由于我们在x floor中使用1 drop,因此等式必须添加1,这反映在等式的第一部分。

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

答案 2 :(得分:0)

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

我相信这是不言自明的..请随意询问是否有任何部分不清楚......将乐意解释

答案 3 :(得分:0)

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

  1. 动态编程
  2. 使用二进制搜索树的解决方案
  3. 通过获得最大楼层数的直接数学公式得出解决方案,该公式可以测试或覆盖给定数量的鸡蛋和给定的滴数
  4. 让我首先定义一些在之后进行的分析中使用的符号:

    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 <= e(蛋的数量)的约束宽度是一种解决方案,但它可能不是最佳解决方案。

    因此,获得最优解决方案等同于获得BST中具有最小高度的节点的布置受到约束:BST的宽度<= e

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

答案 4 :(得分:0)

这个问题并不在于应该丢弃地板蛋的问题,而是要尽量减少掉落数量。

  • 假设我们有n个鸡蛋和k层,
  • 基础案例:
    • 当floor为1时,MinNoOfDrops(n,1)= 1
    • 当鸡蛋为1时,MinNoOfDrops(1,k)= k
  • Generailsed Solution:
  • 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表

  • 基础案例:当鸡蛋为零或一个时,设置为楼层i,表[0] [i] = 0;和表[1] [i] =我

  • 基础案例:楼层为零或一,然后为鸡蛋j设置,表格[j] [0] = 0 和表[j] [1] = 1

  • 将鸡蛋从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])
      • 如果表[i] [j]&gt;然后是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];
    }
}