原题:两个软硬程度一样但未知的鸡蛋,它们有可能都在一楼就摔碎,也可能从一百层楼摔下来没事。有座100层的建筑,要你用这两个鸡蛋确定哪一层是鸡蛋可以安全落下的最高位置。可以摔碎两个鸡蛋。在最坏的情况下最少需要几次测试,才能得到摔碎鸡蛋的楼层?
这个题目的解答网上的答案有很多,本文就不细述了,本文主要在于n层楼,a个鸡蛋在最坏情况下的最少测试次数。
TestNum[floorNum][eggNum]表示floorNum层楼,eggNum个鸡蛋时,最坏情况下的测试次数。
动态规划算法通过将原问题分解为子问题,则:
TestNum[floorNum][eggNum]=min{ max(TestNum[floorNum-i][eggNum]+1, TestNum[i-1][eggNum-1]+1) },
其中i=1,2,...,floorNum
显然
TestNum[k][1]=k,0<=k<=eggNum;
TestNum[0][1...eggNum]=0;
解释如下:
首先在第i层扔鸡蛋,若没有破,则剩余测试次数为 :
TestNum[floorNum-i][eggNum];
若鸡蛋破了,则剩余测试次数为
TestNum[i-1][eggNum-1]
故可以据此写出解决该问题的动态规划算法的程序。
1. 带备忘的自顶向下法
int Memorized_MinTestCount(int floorNum, int eggNum)
{
int **TestNum = new int *[floorNum + 1];
for (int i = 0; i < floorNum + 1; i++)
{
TestNum[i] = new int[eggNum + 1];
}
for (int i = 0; i < floorNum + 1; i++)
{
for (int j = 0; j < eggNum + 1; j++)
{
TestNum[i][j] = 0xFFFFFFFF;
}
}
return Memorized_Up_Bottom_MinTestCount(TestNum, floorNum, eggNum);
}
int Memorized_Up_Bottom_MinTestCount(int **pNum, int floorNum, int eggNum)
{
if (pNum[floorNum][eggNum] >= 0)
{
return pNum[floorNum][eggNum];
}
int minNum = 0xFFFFFFFF;
if (eggNum == 1)
{
minNum = floorNum;
}
else if (floorNum == 0)
{
minNum = 0;
}
else
{
for (int k = 1; k <= floorNum; k++)
{
if (k == 1)
{
minNum = max(Memorized_Up_Bottom_MinTestCount(pNum, floorNum - k, eggNum) + 1, Memorized_Up_Bottom_MinTestCount(pNum, k - 1, eggNum - 1) + 1);
}
else
{
minNum = min(max(Memorized_Up_Bottom_MinTestCount(pNum, floorNum - k, eggNum) + 1, Memorized_Up_Bottom_MinTestCount(pNum, k - 1, eggNum - 1) + 1), minNum);
}
}
}
pNum[floorNum][eggNum] = minNum;
return pNum[floorNum][eggNum];
}
2. 自底向上法
int Bottom_Up_MinTestCount(int floorNum, int eggNum)
{
//分配存储空间
int **TestNum = new int *[floorNum + 1];
for (int i = 0; i < floorNum + 1; i++)
{
TestNum[i] = new int[eggNum + 1];
}
//一个鸡蛋测i层楼最坏情况需要测i次
for (int i = 0; i < floorNum + 1;i++)
{
TestNum[i][1] = i;
}
//不管几个鸡蛋,测0层楼最坏情况需要测试0次
for (int i = 0; i < eggNum + 1;i++)
{
TestNum[0][i] = 0;
}
if (eggNum==1)//如果只有一个鸡蛋,则测试的次数即为楼层数
{
return TestNum[floorNum][1];
}
int i, j, k;
for (i = 2; i < eggNum + 1; i++)
{
for (j = 1; j < floorNum + 1; j++)
{
int minNum;
for (k = 1; k <= j; k++)
{
if (k == 1)
{
minNum = max(TestNum[j - k][i] + 1, TestNum[k - 1][i - 1] + 1);//给minNum赋初始值
}
else
{
minNum = min(max(TestNum[j - k][i] + 1, TestNum[k - 1][i - 1] + 1), minNum);
}
}
TestNum[j][i] = minNum;
}
}
return TestNum[floorNum][eggNum];
}