两个鸡蛋问题混乱

时间:2010-11-13 10:07:25

标签: algorithm

两个鸡蛋问题:

  • 你有2个鸡蛋。
  • 您可以使用100层高的建筑物。
  • 鸡蛋可能非常坚硬或非常脆弱意味着如果从一楼掉落可能会破裂,或者如果从100楼掉落则可能甚至不会破裂。鸡蛋是相同的。
  • 你需要弄清楚一幢100层高的建筑物的最高楼层,一个鸡蛋可以在不破坏的情况下掉落。
  • 现在的问题是你需要多少滴。你可以在这个过程中打破2个鸡蛋

我确信已经充分讨论了两个鸡蛋问题(如上所述)。但是有人可以帮助我理解为什么以下解决方案不是最佳的。

假设我使用段大小为s的分段和扫描算法。 所以,

d ( 100 / s   + (s-1) ) = 0    [ this should give the minima,  I need '(s-1)' scans per segment and there are '100/s' segments]
-
ds

=> -100 / s^2 + 1 = 0
=> s^2 = 100
=> s = 10

所以根据这个,我需要最多19滴。但最佳解决方案可以做到14滴。

问题出在哪里?

10 个答案:

答案 0 :(得分:20)

您似乎在假设大小相等的细分市场。对于最佳解决方案,如果第一个段的大小为N,则第二个段的大小为N-1,依此类推(因为当您开始测试第二个段时,您已经为第一个段丢弃了一个段)。

答案 1 :(得分:7)

所以你需要解决n+(n-1)+(n-2)+...+1<=100,从(n)(n+1)/2<=100(这个函数变换是用arithmetic series算术序列的总和来完成),现在如果求解n({{ 3}}:Reduce[Floor[n + n^2] >= 200, n])你得到14.现在你知道你需要做的第一层是14楼,接下来是(14 + 14-1)楼和整个序列:

14; 27; 39; 50; 60; 69; 77; 84; 90; 95; 99; 100 

如果你打破了第一个鸡蛋,你会回到最后一个鸡蛋并线性检查所有选项,直到你打破第二个鸡蛋,当你这样做时,你得到了答案。没有魔力。

wolframalpha

答案 2 :(得分:6)

正确且最佳的解决方案是13, 25, 36, 46, 55, 64, 72, 79, 85, 90, 94, 97, 99, 100,其中找到鸡蛋休息的楼层的平均试验次数最少,假设鸡蛋断裂的楼层是随机选择的。

基于这些信息,我们可以编写一个递归函数来最小化平均试验,从而得到

的解决方案
13, 25, 36, 46, 55, 64, 72, 79, 85, 90, 94, 97, 99, 100

每个楼层步骤都有以下最大试验

13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14

这显然比通过假设从14开始并减少的差距而得到的天真解决方案要好得多。在这种情况下,55%的时间你只需要13次试验。它非常靠近n (n+1) / 2 >= 100得出的最优解,得到n = 13.651,我们的最优解为(13*5+14*9)/14,即13.643

这是一个快速实施:

import sys

def get_max_trials(floors):
    pf = 0
    trials = []
    for i, f in enumerate(floors):
        trials.append(i+f-pf)
        pf = f
    return trials

def get_trials_per_floor(floors):
    # return list of trials if egg is assumed at each floor
    pf = 0
    trials = []
    for i, f in enumerate(floors):
        for mid_f in range(pf+1,f+1):
            trial = (i+1) + f - mid_f + 1
            if mid_f == pf+1:
                trial -= 1
            trials.append(trial)
        pf = f
    return trials

def get_average(floors):
    trials = get_trials_per_floor(floors)
    score = sum(trials)
    return score*1.0/floors[-1], max(trials)

floors_map = {}
def get_floors(N, level=0):
    if N == 1:
        return [1]
    if N in floors_map:
        return floors_map[N]
    best_floors = None
    best_score = None
    for i in range(1,N):
        base_floors = [f+i for f in get_floors(N-i, level+1)]
        for floors in [base_floors, [i] + base_floors]:
            score = get_average(floors)
            if best_score is None or score < best_score:
                best_score = score
                best_floors = floors

    if N not in floors_map:
        floors_map[N] = best_floors
    return best_floors

floors = get_floors(100)
print "Solution:",floors
print "max trials",get_max_trials(floors)
print "avg.",get_average(floors)

naive_floors = [14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100]
print "naive_solution",naive_floors 
print "max trials",get_max_trials(naive_floors)
print "avg.",get_average(naive_floors)

输出:

Solution: [13, 25, 36, 46, 55, 64, 72, 79, 85, 90, 94, 97, 99, 100]
max trials [13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14]
avg. (10.31, 14)
naive_solution [14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100]
max trials [14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12]
avg. (10.35, 14)

答案 3 :(得分:2)

我也有同样的想法。我也试图找到你所说的确切方法。我解释了这个解决方案,正如其中一位成员所解释的那样。但是如果可能的话,这里有更多的解释。

N被定义为所需搜索的最小数量。

我正试图找到一个no:n,这是我必须做的搜索的最小数量。

所以我从第x层开始,我有2个场景,

1) 它打破了,我必须做x-1更多检查(因为我只有1个鸡蛋)。一切都很公平。总计为1+ x-1 = x次搜索。

现在我们已将此值定义为n。因此x = n! [PS:这可能是微不足道的,但这有一些微妙的IMO]

2) 它没有破坏 - 我已经用尽了我的一种可能性! 现在进一步允许的搜索是n - 1。只有这样,搜索的总数为:N,这就是N的定义。 现在这个问题已经成为100个楼层有2个鸡蛋的子问题。 如果我现在正在选择y-floor,那么最糟糕的情况应该是n-1。 (n - 1)满足了这一点。

因此你得到的模式转到nth , n + (n -1 )th floor , n + (n - 1) + (n - 2)th floor ....解决这个问题在100楼,你得到N. 你认为,你开始的地板和搜索的结果是巧合。

要获得最大值n = 14,您可以想到有两个灯泡同时发光的灯泡。 它将需要至少14个灯泡来覆盖鸡蛋可能破裂的所有可能组合。

作为挑战尝试为3个鸡蛋做。

基本上,在你的逻辑中,搜索进度的方式存在不对称性。 对于第一组10个元素,算法快速找到。 我建议尝试检查

http://ite.pubs.informs.org/Vol4No1/Sniedovich/进行一些探索,并尝试可视化在网络的实际情况中如何看待此问题。

答案 4 :(得分:2)

我在下面的链接中找到的解决方案的一个非常好的解释。 The Two Egg Problem

它解释了你如何到达n+(n-1)+(n-2)+...+1<=100 1蛋问题 - 线性复杂度O(100)
和多个(无限)蛋问题 - 对数复杂度O(log2(100))。

答案 5 :(得分:1)

这是Python的解决方案。如果你将鸡蛋放在某个楼层f,它会破裂或者不会,并且在每种情况下你都需要检查一定数量的楼层(这是一个子问题)。它使用递归和查找字典来使计算速度更快。

neededDict = {}

# number of drops you need to make
def needed(eggs, floors):

    if (eggs, floors) in neededDict:
        return neededDict[(eggs, floors)]

    if eggs == 1:
        return floors

    if eggs > 1:

        minimum = floors
        for f in range(floors):
            #print f
            resultIfEggBreaks = needed(eggs - 1, f)
            resultIfEggSurvives = needed(eggs, floors - (f + 1))
            result = max(resultIfEggBreaks, resultIfEggSurvives)
            if result < minimum:
                minimum = result

        # 1 drop at best level f plus however many you need to handle all floors that remain unknown
        neededDict[(eggs, floors)] = 1 + minimum
        return 1 + minimum


print needed(2, 100)

答案 6 :(得分:1)

问题不应该是你需要多少滴?但是为了知道鸡蛋在哪里打破,应该找到最小数量的水滴,我在businesscup上看到了这个问题,下面是我想到的算法:

有两种方法可以解决这个问题:

一旦第一个鸡蛋被打破,我们知道我们需要看哪个区间:

  1. 二进制示例:

    我们尝试100/2(50)如果它破了我们搜索从1到50递增1如果不是我们从50 + 100/2(75)抛出它如果它打破我们搜索从50到75如果不是我们扔它从75 + 100/2(87)如果它打破我们从75到87搜索一次一层楼,依此类推等等。

  2. fibonacy例子:同样的事情:我们尝试1,2,3,5,8.13,......如果第一个鸡蛋 我们回到最后一个区间的最小值并增加1。

答案 7 :(得分:0)

嘿,这个方法怎么样。

尝试以下顺序:

<强> 1,2,4,8,16,32,64,100

一旦你发现鸡蛋坏了,你就可以获得一个空间。 让我们假设@ 64鸡蛋休息。然后答案介于32&amp; 64。

我们可以在这两个数字之间使用常规二进制搜索。 我们将检查@ 48(32 + 64)/ 2然后我们将上半部分或下半部分作为入围空间。并重复

在这种情况下,最糟糕的情况是发言权为99.这将需要14次尝试。

答案 8 :(得分:0)

对两个鸡蛋问题的解释可能会使一些人在第一时间感到困惑,因此我们可以如下理解解决方案: 给定x是底数,我们开始放鸡蛋: -如果失败,则最坏情况下的总试用次数为 x +(x-1) -如果还没有破裂,我们应该如何进入下一层?我们可以跳到第(x + x)个(x + x + 1)个 ...,但这会增加试验次数,我们可以尝试x = 10:  。如果确实失败,在最坏的情况下我们必须尝试总计10次。  。如果它没有破裂,那么我们升至10th + 10th = 20th并尝试,如果它破裂,我们必须尝试1次(在10层)+1(在20层)+ 9 = 11次。同样,如果我们提高到x + 1或x + 2底数,则会增加试验次数。 实际上,我们希望两种情况下的试验次数相等,因此,我们将提高到x-1楼,而不是x,x + 1等。最后,我们将大致得到一个表达式: x +(x-1)+(x-2)+ ... + 1。 就是这样。

答案 9 :(得分:-1)

我想说100个楼层有两个鸡蛋的最佳解决方案是13次尝试而不是14次 13, 25, 36, 46, 55, 64, 72, 79, 85, 90, 94, 97, 99, 100是最佳答案,但如果我达到99,我真的不需要尝试100.很明显正确答案没有尝试从100楼掉蛋:D