Super Egg Drop

一道陈题.

100 层楼 2 个玻璃球

起因是窥室友手机屏, 看到他群里有人问一个经典问题.

两个一模一样的玻璃球, 两个玻璃球如果从一定高度掉落到地上会被摔碎, 如果在这个高度以下往下扔怎么都不会碎, 现在已知这个恰巧摔碎的高度范围在 1 层楼到 100 层楼之间, 如何用最少的试验次数, 用这两个玻璃球测试出玻璃球恰好摔碎的楼高呢?1

当只剩 1 个球时, 只能一层一层往上测试. 第 1 个球的任务是减少第 2 个球所需测试的次数. 直观上讲, 第 1 个球测试点的间隔要越来越小, 这样第 2 个球所需测试次数少, 才能保证总次数一定.

记最少测试次数为 \(m\), 即最优策略的最坏测试次数为 \(m\). 若第 1 个球第 \(j\) 次测试 (之前都没碎) 在 \(n_j\) 层下落

  • 没碎, 则 \(j+1\) 次测试时, 问题归结为求 \(100 - n_j\) 层楼的最少试验次数.
  • 摔碎, 则第 2 个球要在 \(m-j\) 次内在 \(n_j - n_{j-1} - 1\) 层楼中完成测试. 而第 2 个球 \(m-j\) 次最多只能在 \(m-j\) 层楼中定位临界层数.

因此 2 个球 \(m\) 次测试最多可以在 \(m + (m-1) + \dots + 1 = m(m+1)/2\) 层楼中定位临界层数. 最小测试次数即 \(\min\{m\in\mathbb N \mid m(m+1)/2 \ge 100\} = 14\). 策略并不唯一, 例如令 \(n_j = m + (m-1) + \dots + (m-j+1)\), 其中 \(j\le 11\).

\(N\) 层楼 \(k\) 个玻璃球

一个很自然的问题是, 若有 \(k\) 个玻璃球, 求在 \(N\) 层楼中定位临界层数需要的最少测试次数.2 类似上题, 考虑 \(k\) 个球 \(m\) 次测试最多能在 \(f(k, m)\) 层楼中定位临界层数. 若第 1 个球第 1 次测试在 \(n_1\) 层下落

  • 没碎, 则剩下 \(k\) 个球, \(m-1\) 次机会, 至多还可以在上面的 \(f(k, m-1)\) 层楼中定位临界层数.
  • 摔碎, 则剩下 \(k-1\) 个球, \(m-1\) 次机会, 至多还可以在下面的 \(f(k-1, m-1)\) 层楼中定位临界层数.

因此

\[
f(k, m) = f(k, m-1) + 1 + f(k-1, m-1), \]

边界条件 \(f(0, m) = f(k, 0) = 0\), 或者说 \(f(1,m) = m\), \(f(k,1) = 1\).

这个形式让人很自然地想起了 (广义) 组合数的递推式

\[
\frac{m(m-1)\cdots (m-n+1)}{n!}=\begin{pmatrix}m\\n\end{pmatrix} = \begin{pmatrix}m-1\\n\end{pmatrix} + \begin{pmatrix}m-1\\n-1\end{pmatrix}.
\]

所以要想办法把递推式中的 1 去掉. First attempt 是记 \(g(k,m) = f(k, m) + 1\), 但是这样边界条件不对. 尝试 \(g(k,m) = f(k,m) - f(k,m-1)\) 边界条件也不对. 记 \(g(k,m) = f(k,m) - f(k-1,m)\), 则

\[
g(k,m) = g(k, m-1) + g(k-1, m-1),
\]

这次边界条件对了, \(g(1,m) = m\), \(g(1,1) = 1\), \(g(k,1) = 0\) for \(k>1\). 易知

\[
f(k,m) = \sum_{x=1}^k g(x,m) + f(0,m) = \sum_{x=1}^k\begin{pmatrix}m\\x\end{pmatrix}.
\]

于是 \(k\) 个球 \(N\) 层楼, 最少测试次数是 \(\min\{m \mid f(k,m) \ge N\}\).

class Solution:
    def superEggDrop(self, k: int, N: int) -> int:

        def f_k(m):
        # if f(k, m) >= N, return True; else False
            result = 0
            c = 1
            for x in range(1, k+1):
                c = c * (m-x+1) / x  # combinatorial number C_m^x
                result += c  # f(x, m)
                if result >= N:
                    return True
            return False

        # binary search
        left, right = 1, N
        while left < right:
            mid = (left + right) // 2
            if f_k(mid):
                right = mid
            else:
                left = mid + 1
        return left

算法时间复杂度 \(O(k\log N)\), 空间复杂度 \(O(1)\).


  1. 题目的意思是只要玻璃球不碎, 那么它是不会受到损伤的, 即临界层数 (最低摔碎楼层) 不变. 给定一个策略 \(S\colon \mathbb N \to \mathbb N\), \(S(n)\) 表示临界层数为 \(n\) 时, 该策略需要测试的次数, 则最少测试次数是指 \(\displaystyle \min_S\max_n S(n)\).?
  2. 查了查, LeetCode 887 就有这个问题.?

原文地址:https://www.cnblogs.com/shiina922/p/11516507.html

时间: 2024-08-30 14:32:40

Super Egg Drop的相关文章

Leetcode 887. Super Egg Drop

Problem: You are given K eggs, and you have access to a building with N floors from 1 to N. Each egg is identical in function, and if an egg breaks, you cannot drop it again. You know that there exists a floor F with 0 <= F <= N such that any egg dr

LeetCode887 - Super Egg Drop - Hard (Python)

这是labuladong的文章总结. 这是一题经典的DP问题,DP的框架为首先思考这个问题有什么状态,有哪些选择,最后根据情况穷举所有可行解. 这题的状态即为当前拥有的鸡蛋数k以及当前所在的楼层数n.选择是我们选择去哪一层楼扔鸡蛋.由状态和选择我们可以得到相对应的转移方程(因为有两个状态,鸡蛋数以及楼层数,所以我们可以考虑用二维的数组): dp[k][i] = min(dp[k][i], max(dp[k-1][i-1], dp[k][n-i]) 在i层楼扔鸡蛋,鸡蛋可能碎也可能不碎(状态转移方

【LeetCode】动态规划(下篇)

[600] Non-negative Integers without Consecutive Ones [629] K Inverse Pairs Array [638] Shopping Offers [639] Decode Ways II [646] Maximum Length of Pair Chain [647] Palindromic Substrings [650] 2 Keys Keyboard [651] 4 Keys Keyboard [656] Coin Path [6

【LeetCode】数学(共106题)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica } [2]Add Two Numbers [7]Reverse Integer [8]String to Integer (atoi) [9]Palindrome Number [12]Integer to Roman [13]Roman to Integer [29]Divide Two Integers [43]Multiply Strings [50]Pow(x,

【LeetCode】动态规划(上篇共75题)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica } [5] Longest Palindromic Substring 给一个字符串,需要返回最长回文子串 解法:dp[i][j] 表示 s[i..j] 是否是回文串,转移方程是 dp[i][j] = 1 (if dp[i+1][j-1] = 1 && s[i] == s[j]),初始化条件是 if (s[i] == s[j] && (i == j

【LeetCode】动态规划(下篇共39题)

[600] Non-negative Integers without Consecutive Ones [629] K Inverse Pairs Array [638] Shopping Offers [639] Decode Ways II [646] Maximum Length of Pair Chain [647] Palindromic Substrings [650] 2 Keys Keyboard [651] 4 Keys Keyboard [656] Coin Path [6

【LeetCode】二分 binary_search(共58题)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica } [4]Median of Two Sorted Arrays [29]Divide Two Integers [33]Search in Rotated Sorted Array [34]Find First and Last Position of Element in Sorted Array [35]Search Insert Position [50]Pow(

转载:Pixhawk源码笔记四:学习RC Input and Output

转自:新浪@WalkAnt 第五部分 学习RC Input and Output 参考:http://dev.ardupilot.com/wiki/learning-ardupilot-rc-input-output/ RC Input,也就是遥控输入,用于控制飞行方向.改变飞行模式.控制摄像头等外围装置.ArduPilot支持集中不同RC input(取决于具体的硬件飞控板): 1. PPMSum – on PX4, Pixhawk, Linux and APM2 2. SBUS – on P

mysql 从库设置read-only 对super权限的用户无效的问题

由于在测试mysql主从读写分离的时候,用root用户设置从库为read-only ,但是重启生效后发现,root用户照样可以进行update insert ,此时root用有all privilege权限,包括super(管理)权限 测试单独回收revoke root的super权限后再试,发现root此时 已经不能写操作了 因此在给普通用户,或区分读写分离用户时,注意要回收super权限,否则对read-only无效. 另外为了防止普通用户对从库进行插入,在给用户分配权限时要回收super权