2個雞蛋100層樓--動態規劃
阿新 • • 發佈:2018-12-21
原題:兩個軟硬程度一樣但未知的雞蛋,它們有可能都在一樓就摔碎,也可能從一百層樓摔下來沒事。有座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];
}