Leetcode 887. 鸡蛋掉落【动态规划】

文章目录

  • 问题描述
  • 解题报告
  • 实现代码
  • 参考资料

问题描述

你将获得 K 个鸡蛋,并可以使用一栋从 1N 共有 N 层楼的建筑。

每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。

你知道存在楼层 F ,满足 0 <= F <= N 任何从高于 F 的楼层落下的鸡蛋都会碎,从 F 楼层或比它低的楼层落下的鸡蛋都不会破。

每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层 X 扔下(满足 1 <= X <= N)。

你的目标是确切地知道 F 的值是多少。

无论 F 的初始值如何,你确定 F 的值的最小移动次数是多少?

解题报告

d p [ i ] [ j ] dp[i][j] dp[i][j] 表示有i个鸡蛋,j层楼需要的最小操作数。
转移方程为:
d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , m a x ( d p [ i − 1 ] [ k − 1 ] , d p [ i ] [ j − k ] ) + 1 )        ( 1 ≤ k ≤ j ) dp[i][j]=min(dp[i][j], max(dp[i-1][k-1], dp[i][j-k])+1)\;\;\;(1\le k\le j) dp[i][j]=min(dp[i][j],max(dp[i1][k1],dp[i][jk])+1)(1kj)

注意到 d p [ i − 1 ] [ k − 1 ] , d p [ i ] [ j − k ] dp[i-1][k-1], dp[i][j-k] dp[i1][k1],dp[i][jk] 随着 k k k 的大小是成相反变化的
为了使得 d p [ i ] [ j ] dp[i][j] dp[i][j] 尽可能小,我们应该让 d p [ i − 1 ] [ k − 1 ] , d p [ i ] [ j − k ] dp[i-1][k-1], dp[i][j-k] dp[i1][k1],dp[i][jk] 尽可能相等
所以可以采用二分法来找到这个合适的 k k k 值。

后面的很多优化手段待续。。。

实现代码

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];
    }
};

参考资料

[1] Leetcode 887. 鸡蛋掉落
[2] [LeetCode] 887. Super Egg Drop 超级鸡蛋掉落

你可能感兴趣的:(leetcode,动态规划)