# [LeetCode] 887. Super Egg Drop 超级鸡蛋掉落

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 dropped at a floor higher than Fwill break, and any egg dropped at or below floor Fwill not break.

Each move, you may take an egg (if you have an unbroken one) and drop it from any floor X (with 1 <= X <= N).

Your goal is to know with certainty what the value of F is.

What is the minimum number of moves that you need to know with certainty what F is, regardless of the initial value of F?

Example 1:

Input: K = 1, N = 2
Output: 2
Explanation:
Drop the egg from floor 1.  If it breaks, we know with certainty that F = 0.
Otherwise, drop the egg from floor 2.  If it breaks, we know with certainty that F = 1.
If it didn't break, then we know with certainty F = 2.
Hence, we needed 2 moves in the worst case to know what F is with certainty.

Example 2:

Input: K = 2, N = 6
Output: 3

Example 3:

Input: K = 3, N = 14
Output: 4

Note:

1. 1 <= K <= 100
2. 1 <= N <= 10000

• 鸡蛋碎掉：接下来就要用 i-1 个鸡蛋来测 k-1 层，所以需要 dp[i-1][k-1] 次操作。
• 鸡蛋没碎：接下来还可以用i个鸡蛋来测 j-k 层，所以需要 dp[i][j-k] 次操作。
因为我们每次都要面对最坏的情况，所以在第j层扔，需要 max(dp[i-1][k-1], dp[i][j-k])+1 步，状态转移方程为：

dp[i][j] = min(dp[i][j], max(dp[i - 1][k - 1], dp[i][j - k]) + 1) ( 1 <= k <= j )

class Solution {
public:
int superEggDrop(int K, int N) {
vector<vector<int>> dp(K + 1, vector<int>(N + 1));
for (int j = 1; j <= N; ++j) dp[1][j] = j;
for (int i = 2; i <= K; ++i) {
for (int j = 1; j <= N; ++j) {
dp[i][j] = j;
int left = 1, right = j;
while (left < right) {
int mid = left + (right - left) / 2;
if (dp[i - 1][mid - 1] < dp[i][j - mid]) left = mid + 1;
else right = mid;
}
dp[i][j] = min(dp[i][j], max(dp[i - 1][right - 1], dp[i][j - right]) + 1);
}
}
return dp[K][N];
}
};

class Solution {
public:
int superEggDrop(int K, int N) {
vector<vector<int>> dp(K + 1, vector<int>(N + 1));
for (int j = 1; j <= N; ++j) dp[1][j] = j;
for (int i = 2; i <= K; ++i) {
int s = 1;
for (int j = 1; j <= N; ++j) {
dp[i][j] = j;
while (s < j && dp[i - 1][s - 1] < dp[i][j - s]) ++s;
dp[i][j] = min(dp[i][j], max(dp[i - 1][s - 1], dp[i][j - s]) + 1);
}
}
return dp[K][N];
}
};

• 鸡蛋碎掉：说明至少可以测到的不会碎的层数就是 dp[i-1][j-1]。
• 鸡蛋没碎：那这个鸡蛋可以继续利用，此时我们还可以再向上查找 dp[i-1][j] 层。

dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] + 1

class Solution {
public:
int superEggDrop(int K, int N) {
vector<vector<int>> dp(N + 1, vector<int>(K + 1));
int m = 0;
while (dp[m][K] < N) {
++m;
for (int j = 1; j <= K; ++j) {
dp[m][j] = dp[m - 1][j - 1] + dp[m - 1][j] + 1;
}
}
return m;
}
};

class Solution {
public:
int superEggDrop(int K, int N) {
vector<int> dp(K + 1);
int res = 0;
for (; dp[K] < N; ++res) {
for (int i = K; i > 0; --i) {
dp[i] = dp[i] + dp[i - 1] + 1;
}
}
return res;
}
};


f(k,x) = x(x-1)..(x-k)/k! + ... + x(x-1)(x-2)/3! + x(x-1)/2! + x

class Solution {
public:
int superEggDrop(int K, int N) {
int left = 1, right = N;
while (left < right) {
int mid = left + (right - left) / 2;
if (helper(mid, K, N) < N) left = mid + 1;
else right = mid;
}
return right;
}
int helper(int x, int K, int N) {
int res = 0, r = 1;
for (int i = 1; i <= K; ++i) {
r *= x - i + 1;
r /= i;
res += r;
if (res >= N) break;
}
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/887

https://leetcode.com/problems/super-egg-drop/

https://www.cnblogs.com/Phantom01/p/9490508.html

https://www.acwing.com/solution/leetcode/content/579/

https://leetcode.com/problems/super-egg-drop/discuss/159508/easy-to-understand

https://leetcode.com/problems/super-egg-drop/discuss/299526/BinarySearch-or-Easiest-or-Explanation

https://leetcode.com/problems/super-egg-drop/discuss/158974/C%2B%2BJavaPython-2D-and-1D-DP-O(KlogN)

https://leetcode.com/problems/super-egg-drop/discuss/181702/Clear-C%2B%2B-codeRuntime-0-msO(1)-spacewith-explation.No-DPWhat-we-need-is-mathematical-thought!

posted @ 2019-06-18 22:09  Grandyang  阅读(...)  评论(...编辑  收藏