双蛋问题的递归解法和循环解法

python实现李永乐老师的双蛋问题

https://www.bilibili.com/video/av96214853

一个鸡蛋从高楼扔下,在低楼层不会摔碎,高楼层会摔碎,假设楼共100层,找出临界的楼层,即到这一层鸡蛋正好摔碎,最少要多少次

如果只有1个蛋,那么就只能从第一层扔,碎了就是1,没有到第二楼继续扔,最少要扔100次

如果有两个蛋,就先用第一个蛋确定范围,再用第二个蛋一层层测试

将100层拆分成10次,10,20…,100 ,最多10次,即90-100,之后再用另一个蛋最多扔9次 [1,9] ,最少要扔19次

优化下,最开始扔n层,之后n-1层,之后n-2层……,最后扔1层,这样,每一层扔的次数都一样是n+1,

计算n的值:n+(n-1)+……+1=100,等差数列,(1+n)*n/2=100,n^2+n=200,n^2+n+1/4=200.25,n=(200.25)^(1/2)-0.5=13.65,n取14

14,27,39,50,60,69,77,84,90,95,99,100 ,最多扔了12次,那最少要扔14次,

问题拓展,假如我有n个蛋,楼总共有t层楼,计算出最少要扔多少次 记为M

式子为:M=fun(n,t),

1.当n为1时,总是有M=t,

2.当t=1时,总是有M=1,

也就是问题至少要是2个蛋,楼有两层,即fun(2,2),才开始计算。

先扔第一个鸡蛋,在第k层扔,1<=k<=t;

两种结果,1、碎,临界楼层在1到k层,下一次扔fun(n-1,k),之中。

2、不碎,临界楼层在上面,fun(n,t-k),之中,

取两者的最大值,max{ fun(n-1,k-1) , fun(n,t-k) } + 1

k需要从第1层,一直第t层,这样找出最小的 max{ fun(n-1,k-1) , fun(n,t-k) } + 1 的值,

作为f(n,t)的值

fun(2,2)=min{ fun(2,1) , fun(1,2) } + 1 ; #因为要比上一种多扔最后一次。

--按照李永乐老师的递归思想,程序开销很大,楼层越高开销越大,之后改成循环做处理

式子为:M=fun(n,t),

1.当n为1时,总是有M=t,

2.当t=1时,总是有M=1,

 


def fun_recursion(v_floors, v_eggs):
    if v_eggs == 1:
        return v_floors
    if v_floors == 1:
        return 1
    if v_eggs == 0 or v_floors == 0:
        return 0;

    v_min = 1000000;
    for i in range(1, v_floors + 1):
        result_1 = fun_recursion(i - 1, v_eggs - 1) + 1;
        result_2 = fun_recursion(v_floors - i, v_eggs) + 1;
        v_min = min(v_min, max(result_1, result_2));
    return v_min


# 循环 动态规划思想,全局最优解包含局部最优解,由局部最优解拓展到全局最优解
# 先建立二维列表保存结果数据,将只有1个鸡蛋和只有1层楼的情况填写到列表中, 之后再有局部解推出全局解
def fun_cycle(v_floors, v_eggs):  # 5 2
    list_2d = [[0 for col in range(v_eggs)] for row in range(v_floors)]  # 用于保存局部解存放楼层和鸡蛋的值,第一维度为楼层数,第二维度为鸡蛋数
    # list_2d[v_floors][v_eggs]

    for m in range(v_floors):  # 只有1个鸡蛋时
        list_2d[m][0] = m + 1;

    for m in range(v_eggs):  # 只有1层楼时
        list_2d[0][m] = 1;

    # 从两个蛋,两层楼 逐步开始求解
    for v_floor in range(1, v_floors):
        for v_egg in range(1, v_eggs):
            # k记录第一个蛋扔的层数,从第二层开始扔
            v_min = 1000000;
            for k in range(1, v_floor + 1):
                result_1 = list_2d[k - 1][v_egg - 1]  # 蛋碎了,临界楼层应该在k-1
                result_2 = list_2d[v_floor - k - 1][v_egg]  # 蛋没碎,临界楼层应该在j-k
                v_max = max(result_1, result_2) + 1
                v_min = min(v_min, v_max)
            list_2d[v_floor][v_egg] = v_min

    # 打印循环结果
    for i in range(v_floors):
        print(list_2d[i])
    return list_2d[v_floors - 1][v_eggs - 1]


# 打印递归结果
for i in range(1, 20):
    for j in range(1, 10):
        print(fun_recursion(i, j), end=' ')
    print('')

# print(fun_cycle(20, 10))
# print(fun_recursion(2, 3))

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值