这是经典的扔鸡蛋的题目。 同事说之前在uva上见过,不过是扔气球。题意以下:测试
你有K个鸡蛋,在一栋N层高的建筑上,被要求测试鸡蛋最少在哪一层正好被摔坏。
你只能用没摔坏的鸡蛋测试。若是一个鸡蛋在上一次测试中没有被摔坏,那么你能够重复使用,不然,你只能用下一个鸡蛋。
须要求,最小的步数,使得你在这么多步内必定测试出结果。code
O(K * N^2)
首先,这个题比较绕。须要求一个最优决策使得步数最小,可是实际的步数是随着真实结果变化而变化的。
因而,为了保证在咱们假设的步数内必定可以解完,咱们能够假设每次决策都会获得最坏结果。class
dp[n][k] 表示用k个鸡蛋测n层最少须要多少步。
咱们能够枚举第一次在第i层扔鸡蛋,会获得两种结果:co
因此咱们的递推式以下:
dp[n][k] = min{ max(dp[i-1][k-1], dp[n-i][k]) + 1 } (1 <= i <= n)枚举
const int MAXK = 100, MAXN = 100; int max(int a, int b) {return a > b ? a : b;} int min(int a, int b) {return a < b ? a : b;} int superEggDrop(int K, int N) { int dp[MAXN+2][MAXK+2]; for (int i = 0; i <= MAXN; i++) { dp[i][0] = 0; dp[i][1] = i; } for (int j = 2; j <= MAXK; j++) { for (int i = 1; i <= MAXN; i++) { dp[i][j] = i; for (int k = 1; k < i; k++) { dp[i][j] = min(dp[i][j], max(dp[k-1][j-1], dp[i-k][j]) + 1); } } } return dp[N][K]; }
咱们能够改变一下求解的思路,求k个鸡蛋在m步内能够测出多少层:
假设: dp[k][m] 表示k个鸡蛋在m步内最多能测出的层数。
那么,问题能够转化为当 k <= K 时,找一个最小的m,使得dp[k][m] <= N。return
咱们来考虑下求解dp[k][m]的策略:
假设咱们有k个鸡蛋第m步时,在第X层扔鸡蛋。这时候,会有两种结果,鸡蛋碎了,或者没碎。
若是鸡蛋没碎,咱们接下来会在更高的楼层扔,最多能肯定 X + dp[k][m-1] 层的结果;
若是鸡蛋碎了,咱们接下来会在更低的楼层扔,最多能肯定 Y + dp[k-1][m-1] 层的结果 (假设在第X层上还有Y层)。
所以,此次扔鸡蛋,咱们最多能测出 dp[k-1][m-1] (摔碎时能肯定的层数) + dp[k][m-1] (没摔碎时能肯定的层数) + 1 (本层) 层的结果。
另外,咱们知道一个鸡蛋一次只能测一层,没有鸡蛋一层都不能测出来。
所以咱们能够列出完整的递推式:
dp[k][0] = 0
dp[1][m] = m (m > 0)
dp[k][m] = dp[k-1][m-1] + dp[k][m-1] + 1 (k > 0, m>0)const
// NOTE: 第一维和第二维换了下位置 int superEggDrop(int K, int N) { int dp[N+2][K+2]; memset(dp, 0, sizeof(dp)); dp[0][0] = 0; for (int m = 1; m <= N; m++) { dp[m][0] = 0; for (int k = 1; k <= K; k++) { dp[m][k] = dp[m-1][k] + dp[m-1][k-1] + 1; if (dp[m][k] >= N) { return m; } } } return N; }