https://blog.csdn.net/Sirius_han/article/details/81152572
题目:
现有两个硬度相同的鸡蛋,以及一栋100层的楼,如果鸡蛋在第n层楼摔下去不会碎,在n-1层楼摔下去会碎,那么鸡蛋的硬度是n,如果要测出鸡蛋的硬度n,在最坏情况下最少要测试几次?每测试一次就把一个鸡蛋从x层楼扔下去;只有两个鸡蛋可用,鸡蛋摔碎了就不能用了;
题目分析:
1:二分????
刚开始看到这个题脑子里最先蹦出来的就是二分;每次取一半,log(n)的算法,然后稍微深入分析一下就悲剧了;
按照二分思路,第一个鸡蛋在50层扔下,没有碎;75层,还没碎;88层,仍然坚强不碎;94层,还是一如既往的坚固;97层,还不碎????!!!;99层,,,,,,100层;7次就测出来了;你这么能咋不直接从100层扔鸡蛋?直接不碎,1次就测出来了。。。
注意题目要求最坏情况;什么是最坏情况?第一个鸡蛋50层就碎了,还剩一个鸡蛋,此时你只能乖乖的从第1层开始测试,不然的话,50层之后直接到25层,第二个鸡蛋也碎了就测不出鸡蛋的强度了;
所以二分在最坏情况下需要测50次:第一个鸡蛋在50层碎了,第二个鸡蛋从第一层测试到49层:1+49=50;
2:分段????
第一次测x层,没破测2*x层,依次递推,如果在i*x层破了,就从(i-1)*x+1层开始一直测到i*x层,
经过计算发现最优的x是8, 9, 10, 11, 12, 13,此时需要测k=19次(100/x+(x-1));
这个好像比较靠谱,19次就能测出来,比二分靠谱多了;难道就没有更好的方法了吗????
3:递推!!!
如果第一次扔鸡蛋,鸡蛋就碎了,那么第二个鸡蛋一定是从1层向上测试,此时如果第一次在第k层楼扔鸡蛋,鸡蛋卒,最坏情况下还需测k-1次,共计k次;现在我们假设最少就需要k次能测出鸡蛋硬度,第一次扔鸡蛋,鸡蛋卒的情况下最优解是k,若第一次鸡蛋生,第二次扔鸡蛋鸡蛋卒最优解也要是k的话,第二次一定在第k+k-1=2*k-1层楼扔鸡蛋,因为在第二次扔鸡蛋,鸡蛋卒后,就需要由第k+1层测试到第2*k-2层,测试了k-2次,共计1+1+k-2=k次;同理,如果第二次扔鸡蛋,鸡蛋未卒,第三次扔鸡蛋,鸡蛋卒,则第三次在第k+(k-1)+(k-2)层扔鸡蛋。。。依次递推当前k-1次鸡蛋都逃出生天,到第k次扔鸡蛋时已经该测试第k+(k-1)+(k-2)+(k-3)+···+1=(k+1)*k/2层楼了,也就是说,此楼最多(k+1)*k/2层才能通过最少k次测出鸡蛋硬度;
综上所述:当(k+1)*k/2>=n时,一定可以用k次测出在n层楼上鸡蛋的强度;
对于一个给定的n,取最小的k满足上式,k就是最优解;
当n=100时,k=14时最优;
4:动态规划!!!!
是不是很惊讶???!!!这样也能DP!!!
若n为楼层总数, 令f[n]为总共n层楼时的最优解;在第i层楼如果鸡蛋碎了, f[i]=i-1+1(从第一层开始测试);如果鸡蛋未碎, f[i]=f[n-i]+1(在剩下的n-i层楼测试最优解);所以:f[i]=max(i-1, f[n-i])+1;
f[n]=min(max(i-1, f[n-i])+1 | i=1, 2, 3, 4, ···, n);
#include<bits/stdc++.h>
using namespace std;
int main(){
int f[105];
f[0]=0;
for(int i=1; i<=100; i++){
f[i]=i;
for(int j=1; j<=i; j++){
f[i]=min(f[i], max(j-1, f[i-j])+1);
}
}
cout << f[100] << endl;
return 0;
}
将该题扩展一下, n层楼,m个鸡蛋如何推出最优解?
还是用DP做一下:f[n][m]表示n层楼m个鸡蛋时的最优解;
在第i层,有j个鸡蛋时,本次测试鸡蛋卒,f[i][j]=f[i-1][j-1]+1(用剩下的j-1个鸡蛋测试i-1层),鸡蛋生还f[i][j]=f[n-i][j]+1(继续用j个鸡蛋测试剩下的n-i层);f[i][j]=max(f[i-1][j-1], f[n-i][j])+1;
所以f[n][m]=min(max(f[i-1][j-1], f[n-i][j])+1 | i=1, 2, 3, 4, ···, n)
#include<bits/stdc++.h>
using namespace std;
int main(){
int f[105][105];
for(int i=0; i<=100; i++){
f[i][1]=i;
}
for(int j=2; j<=100; j++)
for(int i=1; i<=100; i++){
f[i][j]=i;
for(int k=1; k<=i; k++){
f[i][j]=min(f[i][j], max(f[k-1][j-1], f[i-k][j])+1);
}
}
cout << f[100][2] << endl;
return 0;
}