经典动态规划——高楼扔鸡蛋(初阶版)

先看题目:

你⾯前有⼀栋从 1 到 N N 层的楼,然后给你 K 个鸡蛋 ( K ⾄少为 1)。现在确定这栋楼存在楼层 0 <= F <= N ,在这层楼将鸡 蛋扔下去,鸡蛋恰好没摔碎(⾼于 F 的楼层都会碎,低于 F 的楼层都不 会碎)。现在问你,最坏情况下,你⾄少要扔⼏次鸡蛋,才能确定这个楼层 F 呢?

那么这个题目一个如何理解?

首先假设鸡蛋数目不限,我们姑且认为鸡蛋刚好在7层楼碎:那么最坏的情况下就是我们拿着鸡蛋从一楼到六楼去丢鸡蛋,直到第七楼鸡蛋碎(当然要是你直接第七楼扔碎也行,但是这只是运气问题并不是最坏情况) ,那么这个样子的话我们需要扔7次。我们将一层一层逐层扔鸡蛋的方式称为线性查找方式

那么如何减少扔鸡蛋的方式以达到“最少”?有一种办法是二分法查找:

最好的策略是使⽤⼆分查找思路,我先去第 (1 + 7) / 2 = 4 层扔⼀下:
如果碎了说明 ⼩于 4 ,我就去第 (1 + 3) / 2 = 2 层试 ……
如果没碎说明 ⼤于等于 4 ,我就去第 (5 + 7) / 2 = 6 层试 ……
但是!一旦鸡蛋数目有限制,就无法一味的使用二分法查找了:例如我只有一个鸡蛋,按照二分法查找我应该去第4楼扔下,但是如果鸡蛋碎掉,就导致无鸡蛋可以扔的地步。因此只能线性查找。
那么来看看我们的状态转移方程:
当鸡蛋没碎:dp(K,N - i)  鸡蛋没碎,即往i层以上层楼层去查找
当鸡蛋碎了:dp(K-1,i-1) 鸡蛋碎了,鸡蛋数目减一,往i层以下查找
def dp(K, N):
    if N == 0: return 0#如果楼层为0,则不需要操作了
    if K == 1: return N#如果鸡蛋只剩一个,则只能逐低至高线性搜索
    res = float("INF")#将res设置为正无穷
    for i in range(1, N + 1):
        res = min(res,
                  max(dp(K - 1, i - 1), dp(K, N - i)) + 1
                  )
    return res

当然这样的函数时间复杂度过于大,因为存在过多的重叠子问题

这边建立一个demo数组来作为备忘录,消除重叠子问题:

# K个鸡蛋,共测试N层楼
demo = dict()#建立备忘录
def dp(K, N):
    if N == 0: return 0#如果楼层为0,则不需要操作了
    if K == 1: return N#如果鸡蛋只剩一个,则只能逐低至高线性搜索
    res = float("INF")
    if (K,N) in demo: return demo[(K,N)]#备忘录查找,如果找到直接访问结果
    for i in range(1, N + 1):
        res = min(res,
                  max(dp(K - 1, i - 1), dp(K, N - i)) + 1
                  )
    demo[(K, N)] = res#写入备忘录
    return res

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值