1. 程式人生 > >2個雞蛋100層樓--動態規劃

2個雞蛋100層樓--動態規劃

原題:兩個軟硬程度一樣但未知的雞蛋,它們有可能都在一樓就摔碎,也可能從一百層樓摔下來沒事。有座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];
}