问题提出:
有座100层的建筑,鸡蛋从某一层扔下来有可能摔碎(可能是1楼,也可能是100楼)。
你手上有两个软硬程度一样的鸡蛋,要判断出来哪一层是鸡蛋可以安全落下的最高位置。
最少需要扔多少次?
解题思路:
》 最笨的方法,从1层开始,每层都扔1次,直到摔碎 为止,得到当前当前层数 n。 最差需要100次
好像只需要一个鸡蛋就够了,明显不对。
》 参照折半搜索算法,第一个鸡蛋跑到 第50层扔下,
没摔碎的话,从第51层开始扔,每次+1;
摔碎的话,从第1层开始扔,每次+1; 最差需要50次
二叉树貌似也不太靠谱,哈哈。
》 多折几次看看:
鸡蛋一: 10、20、30、40……
鸡蛋二: x+1、x+2、x+3、x+4……
这回靠谱了吧? 最差只需要20次了。
这个方案有一个问题:
如果在10层第一个鸡蛋就碎了,那么 Total 最多是11次;
20层 最多 12次
30层 最多 13次
》 问题就是不均匀,很明显我们能想到等差数列。
假设 最少判断次数为 x,鸡蛋一 第一次从第x层扔(不管碎没碎,还有x-1次尝试机会)。
如果碎了,鸡蛋二 在1~x-1层中线性搜索,最多x-1次;
如果没碎,鸡蛋一 第二次从x+(x-1)层扔(现在还剩x-2次尝试机会)。
如果这次碎了,鸡蛋二 在x+1~x+(x-1)-1层中线性搜索,最多x-2次;
如果没碎 鸡蛋一 再从x+(x-1)+(x-2)层扔,依此类推……
x 次尝试所能确定的最高楼层数为x+(x-1)+(x-2)+...+1 = x(x+1)/2
针对200楼层的情况,可以得到 x = 14,最少需要14次。
其实这是一个动态规划问题,给出c++代码:
/* linolzhang 2009.11
drop eggs
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
int drop[9999][99]; // drop[i][j]: 表示在 i 层楼 还有 j 个鸡蛋的最小判断次数
void Solve(int Layers, int Eggs)
{
memset( drop, 0, sizeof(drop) );
for(int i=1; i<=Layers; i++) // 只有一个鸡蛋,肯定是从第一层往上尝试
drop[i][1] = i;
for(int i=1; i<=Eggs; i++) // 只有一层
drop[1][i] = 1;
for(int i=1; i<=Layers; i++)
{
for(int j=2; j<=Eggs; j++)
{
drop[i][j] = INT_MAX;
for(int k=1; k<=i; k++)
drop[i][j] = std::min( drop[i][j],std::max(drop[k-1][j-1], drop[i-k][j])+1 );
}
}
}
int main()
{
printf("请输入楼层数和鸡蛋个数,中间空格:\n");
int Layers, Eggs;
scanf("%d %d",&Layers, &Eggs);
Solve(Layers, Eggs);
printf("最多需要次数: %d\n",drop[Layers][Eggs]);
printf("\nPress Any Key To Continue...");
getchar();
return 0;
}