高楼扔鸡蛋问题
问题描述:一共有n层楼,和m个鸡蛋,要保证最大多少层楼可以保证鸡蛋不碎,需要最少的测试次数。
1、若鸡蛋个数足够多,使用二分法肯定是最优解
最坏情况下的最少测试次数:ceil(logn)
2、若鸡蛋个数不够,这个时候就不能使用二分法了
我们使用动态规划来解决一下这类问题。
1、拆分子问题
若从k层扔下,可以用于测试的鸡蛋有m个
这时有两种情况:a、鸡蛋碎了,这时应该去k层下面进行测试,鸡蛋个数减一。b、鸡蛋没碎,这时可以去第k层上面进行测试,鸡蛋个数不变
dp[k][m]=min{dp[k][m],max{dp[k-1][m-1],dp[n-k][m]}+1}
那么第层的最少测试次数可以总结为dp[k][m]表示当前层是测试的最后一层,或者从第k层的上面或下面找到最坏情况的测试次数,加一表示当前层测试了一次。
`
include <bits/stdc++.h>
using namespace std;
int dp[1005][105]; // 假设最大n和m分别为1000和100
int test(int n, int m) {
if (m == 1)
return n;
if (n == 0)
return 0;
if (dp[n][m] != -1)
return dp[n][m];
int ret = numeric_limits<int>::max();
int low = 1, high = n;
while (low <= high) {
int mid = (low + high) / 2;
int break_case = test(mid - 1, m - 1);
int no_break_case = test(n - mid, m);
// We take the worst case scenario
int temp = max(break_case, no_break_case) + 1;
if (break_case > no_break_case) {
high = mid - 1;
} else {
low = mid + 1;
}
ret = min(ret, temp);
}
return dp[n][m] = ret;
}
int main() {
int n, m;
cin >> n >> m;
memset(dp, -1, sizeof(dp));
cout << test(n, m);
return 0;
}
`
时间复杂度:O(nmlogn)