[动态规划] 谷歌鸡蛋问题

 

问题:

现有2个鸡蛋硬度相同,100层的楼房。鸡蛋从某一层楼房扔下时,可能会破碎。为找出使鸡蛋破碎不破碎的最高楼层f(0<=f<=100),需要做x次实验,求x的最小值。

扩展问题:

先有M个鸡蛋,N层楼房,为找出使鸡蛋不破碎的最高楼层,需要做x次实验,求x的最小值。

  


 

问题分析:

这个问题刚拿到时,很容易想到用二分法求解,因为看上去很像有序集合的查找。确实,若鸡蛋数量足够多,二份法是最快的求解方式,需要log2100向上取整次。若鸡蛋在f层破碎,则在[1,f-1]区间查找,若不破碎则在[f+1,100]区间内求解。但是,当鸡蛋数量小于二分法所需的数量时,就不能用二份法求解。特别地,当只有一个鸡蛋时,应该从1层向上逐渐测试每一层。

 

从测试的第一步开始考虑,此时有两个鸡蛋且未做任何实验。第一次在f1层进行实验,可能有两种结果,破碎或不破碎。若鸡蛋在f1层破碎,则剩下的问题是在[1, f1-1]层中查找,且只剩1个鸡蛋;若鸡蛋在f1层不破碎,则剩下的问题是在[f1+1,100]层中查找,且剩下2个鸡蛋。可以看出,子问题有两个影响因素,所剩楼层及所剩鸡蛋。

定义f(n,m)为有m个鸡蛋,n层楼房,需要的最小实验次数。已知f(0,m) = 0,根据之前的分析又有f(n, 1) = 1。可以写出递归公式。

f(n,m) = min(i from 1 to n) ( max( f(i-1, m-1), f(n - i - 1, m)) ) + 1

可以利用动态规划求解。

 

以15层2个鸡蛋为例求解。

  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
2 0 1 2 2 3 3 3 3 4 4 4 5 5 5 5 5

 

 

 

 

 

利用该递归关系,可以解出100楼2个鸡蛋最少需要14次测试。

 


 

代码示例:

import sys

g_res_table = []

def Compute(floor, egg):
    global g_res_table
    if floor <= 0 or egg <= 0:
        return -1
    
    # initial result table
    for i in range(0, floor + 1):
        lst_floor = []
        for j in range(0, egg + 1):
            lst_floor.append(0)
        g_res_table.append(lst_floor)    
    
    for i in range(1, egg + 1):
        g_res_table[1][i] = 1
        g_res_table[0][i] = 0
    
    # initial value
    for i in range(0 ,floor + 1):
        g_res_table[i][1] = i

    for i in range(2, floor + 1):
        for j in range(2, egg + 1):
            tmp_min = -1
            for cur in range(1, i + 1): 
                if g_res_table[cur - 1][j - 1] > g_res_table[i - cur][j]:
                    max_value = g_res_table[cur - 1][j - 1]
                else:   
                    max_value = g_res_table[i - cur][j] 
                if max_value < tmp_min or tmp_min == -1:
                    tmp_min = max_value
            g_res_table[i][j] = 1 + tmp_min        

    return g_res_table[floor][egg]        

def main(): 
    floor = int(sys.argv[1])
    egg = int(sys.argv[2])
    res = Compute(floor, egg)
    print res

if __name__ == '__main__':
    main()

 

 

posted @ 2012-09-03 10:25  苦力笨笨  阅读(631)  评论(0编辑  收藏  举报