100層樓2個雞蛋,如何得知雞蛋能承受幾層的撞擊

有一棟樓共100層,一個雞蛋從第N層及以上的樓層落下來會摔破, 在第N層以下的樓層落下不會摔破。給你2個雞蛋,設計方案找出N,並且保證在最壞情況下, 最小化雞蛋下落的次數。

我們先假設最壞情況下,雞蛋下落次數爲x,即我們爲了找出N,一共用雞蛋做了x次試驗,那麼,我們第一次應該從哪層樓往下扔雞蛋呢?先讓我們假設第一次是在第y層樓扔的雞蛋,如果第一個雞蛋第一次扔的時候就摔碎了,我們就剩下一個雞蛋,要用它準確的找出N,只能從第一層向上,一層一層的往上測試,直到它摔壞爲止,答案就出來了。由於第一個雞蛋在第y層就摔碎了,所以最壞的情況是第二個雞蛋要把第1到第y-1層的樓都測試一遍,最後得到結果。原來雞蛋在第y-1層才能摔破(或是在第y-1層仍沒摔破,答案就是第y層)。這樣一來,測試次數是1+(y-1)=x,即第一次測試要在第x層。

OK, 那如果第一次測試雞蛋沒摔破呢,那N肯定比要比x大,要繼續往上找,需要在哪一層扔呢?我們可以模仿前面的操作,如果第一個雞蛋在第二次測試中摔破了, 那麼第二個雞蛋的測試次數就只剩下x-2次了(第一個雞蛋已經用了2次)。 這樣一來,第二次扔雞蛋的樓層和第一次扔雞蛋的樓層之間就隔着x-2層。 我們再回過頭來看一看,第一次扔雞蛋的樓層在第x層,第1層到第x層間共x層; 第1次扔雞蛋的樓層到第2次扔雞蛋的樓層間共有x-1層(包含第2次扔雞蛋的那一層), 同理繼續往下,我們可以得出,第2次扔雞蛋的樓層到第3次扔雞蛋的樓層間共有x-2層, ……最後把這些互不包含的區間數加起來,應該大於等於總共的樓層數量100,即:

x + (x-1) + (x-2) + ... + 1 >= 100
(x + 1) * x / 2 >= 100

得出答案是14。

即我先用第1個雞蛋在以下序列表示的樓層數不斷地向上測試,直到它摔破。 再用第2個雞蛋從上一個沒摔破的序列數的下一層開始,向上測試, 即可保證在最壞情況下也只需要測試14次,就能用2個雞蛋找出從哪一層開始, 往下扔雞蛋,雞蛋就會摔破。

14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100

比如,我第1個雞蛋是在第77層摔破的,那麼我第2個雞蛋就從第70層開始,向上測試, 第二個雞蛋最多只需要測試7次(70,71,72,73,74,75,76),加上第1個雞蛋測試的 7次(14,27,39,50,60,69,77),最壞情況只需要測試14次即可得出答案。

這個問題還有一個泛化的版本,即d層樓,e個雞蛋,然後設計方案找出N, 使最壞情況下測試的次數最少。這個要用動態規劃(DP)來解。

f[d][e]表示d 層樓,e個雞蛋時,最壞情況下的測試次數,則:

f[d][e]=min{max(f[d-i][e]+1,f[i-1][e-1]+1)},i=1,2,...,d;

f[k][1]=k,0<=k<=d,f[0][0...e]=0;
int min_testnumber(int e, int d){
    vector<vector<int>> dp(e + 1, vector<int>(d + 1));
    for (int i = 1; i <= e; i++){
        for (int j = 1; j <= d; j++)
            dp[i][j] = j;  //最壞情況下的步數
    }

    for (int i = 2; i <= e; i++){
        for (int j = 1; j <= d; j++){
            for (int k = 1; k < j; k++){
                dp[i][j] = min(dp[i][j], max(dp[i - 1][k - 1], dp[i][j - k]) + 1);
            }
        }
    }
    return dp[e][d];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章