总结 扔鸡蛋问题——1

前言

最近我在知乎上看到了一个扔鸡蛋的问题[1],问题描述如下。在网上学习后,将相关知识整理如下。

正文

问题

有一个 n 层的建筑。如果一个鸡蛋从第 k 层及以上落下,它会碎掉。如果从低于这一层的任意层落下,都不会碎。

有 2 个鸡蛋,用最坏的情况下实验次数最少的方法去找到k, 返回最坏情况下所需的实验次数。

拓展:若有m个鸡蛋,返回最坏情况下所需的实验次数。

测试用例:
m = 2, n=100 → t = 14
m = 2, n = 36 → t = 8

思路及步骤

定义用 m 个蛋在 n 层大楼上最坏情况下确认 k 的所需试验次数,记为 f(n, m),易知 m >= 1 ,f(0, m) = 0,f(n, 1) = n

f(n, 2) 的情况

我们可以把任何一种策略都看成一个决策树, 每一次扔瓶子都会有两个子节点, 对应碎与不碎的情况下下一步应该扔的楼层。
那么, 策略的一次执行, 是树中的一条从根往下走的路, 当且仅当这条路上出现过形如 k 层没碎 与 (k+1)层 碎了的一对节点时, 路停止, 当前节点不再扩展。那么要找的是这么一棵树, 使得所有路里最长者尽量短, 也即, 要找一个最矮的决策树。
再看一个节点处, 选择楼层时会发生什么。容易看出, 选择的楼层如果变高, 那么"碎子树"高度不减, "不碎子树"高度不增。同样的, 选择的楼层变矮的话, "碎子树"高度不增, "不碎子树"高度不减。
这时候答案很明显了: 为了使两子树中高度最大者尽量小, 我们的选择应当使两子树高度尽量接近.最终希望的结果是, 整个二叉树尽量像一个满二叉树。
假设第一次在根节点上, 我们选择扔k层, 其"碎子树"的高度显然是k - 1。为了考虑不碎子树的高度, 设不碎后第二次扔m层(显然m > k ), 则这个新节点的碎子树高度为 m - k - 1, 不碎子树高度仍然未知, 但按照满二叉树的目标, 我们认为它与碎子树相同或少1就好。那么在根节点上的不碎子树的高度就是m -k-1 + 1, 令它与碎子树高度相同, 于是: m - k - 1 + 1 = k - 1 => m = k + k - 1。
也即, 如果第一次扔在k层, 第二次应该高 k-1 层, 这可以有直观一点的理解:每扔一次, 就要更保守一些, 所以让区间长度少1. [1, k) -> [k + 1, 2k - 1)。用类似刚才的分析, 可以继续得到, 下一次应该增高k - 2, 再下一次应该增高k - 3。

可以得出,此时有 k + (k-1) + (k-2) + …… + 1 = n,所求得的k值即为 f(n, 2) 的值。

f(n, m) 的情况

考虑在第w层扔下鸡蛋,情况有两种:

  • 鸡蛋碎了。则可知 k < w,此时问题转化为 w-1 层大楼,m-1 个鸡蛋的情况,这是本问题的一个子问题,可得结果为 f(w-1, m-1)
  • 鸡蛋没碎。则可知 k >= w,此时问题转化为在此上 n-w 层大楼确定 k 的值。类比概率论,此操作是无记忆的,相当于 n-w 层大楼,m 个鸡蛋的情况,这是本问题的一个子问题,可得结果为 f(n-w, m)

综上所述,由上述两种情况可知,最坏情况下的最小值 f(n, m) = min{ max{ f(i-1, m-1), f(n-i, m)} + 1 | 1<=i<=n } 。此算法时间复杂度为O(mn2),由于当 m>n 时,令 m=n 不影响结果,则O(mn2)=O(n3)。空间复杂度为O(n)。

下限的优化

考虑最坏情况,如上所言,此二叉树的叶子结点有(n+1)个,则树的高度至少为⌈log2(n+1)⌉+1,而二分寻找的最坏情况也为⌈log2(n+1)⌉。所以⌈log2(n+1)⌉是一个可达的下限。换而言之,对任意的n,无论m取何值,f(n, m)的值均不会小于⌈log2(n+1)⌉。一旦 m>=⌈log2(n+1)⌉,可直接输出⌈log2(n+1)⌉,时间复杂度降为O(n2 log n)。

参考资料

[1]一幢 200 层的大楼,给你两个鸡蛋。如果在第 n 层扔下鸡蛋,鸡蛋不碎,那么从第 n-1 层扔鸡蛋,都不碎。这两只鸡蛋一模一样,不碎的话可以扔无数次。最高从哪层楼扔下时鸡蛋不会碎?
[2]Problem of Two Eggs
[3]教你彻底理解动态规划——扔鸡蛋问题 Drop Eggs2
[4]优化,再优化!——从《鹰蛋》一题浅析对动态规划算法的优化

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值