Leetcode 887 Super Egg Drop(扔雞蛋) DP


這是經典的扔雞蛋的題目。 同事說以前在uva上見過,不過是扔氣球。題意如下:

題意:

你有K個雞蛋,在一棟N層高的建築上,被要求測試雞蛋最少在哪一層正好被摔壞。
你只能用沒摔壞的雞蛋測試。如果一個雞蛋在上一次測試中沒有被摔壞,那么你可以重復使用,否則,你只能用下一個雞蛋。
需要求,最小的步數,使得你在這么多步內一定測試出結果。

思路:

O(K * N^2)
首先,這個題比較繞。需要求一個最優決策使得步數最小,但是實際的步數是隨着真實結果變化而變化的。
於是,為了保證在我們假設的步數內一定能夠解完,我們可以假設每次決策都會得到最壞結果。

dp[n][k] 表示用k個雞蛋測n層最少需要多少步。
我們可以枚舉第一次在第i層扔雞蛋,會得到兩種結果:

  1. 雞蛋壞掉: 我們接下來需要面對的情形是: 用 k-1 個雞蛋來測量 i-1 層,所以最少需要 dp[i-1][k-1] 步。
  2. 雞蛋沒壞: 我們接下來要面對的情形是: 用 k 個雞蛋來測量 n-i 層,所以最少需要 dp[n-i][k] 步。
    因為我們總會面對最壞情況,所以,在第i層扔,會用 max(dp[i-1][k-1], dp[n-i][k]) + 1 步。

所以我們的遞推式如下:
dp[n][k] = min{ max(dp[i-1][k-1], dp[n-i][k]) + 1 } (1 <= i <= n)

代碼:

const int MAXK = 100, MAXN = 100;

int max(int a, int b) {return a > b ? a : b;}
int min(int a, int b) {return a < b ? a : b;}

int superEggDrop(int K, int N) {
    int dp[MAXN+2][MAXK+2];
    for (int i = 0; i <= MAXN; i++) {
        dp[i][0] = 0;
        dp[i][1] = i;
    }
    for (int j = 2; j <= MAXK; j++) {
        for (int i = 1; i <= MAXN; i++) {
            dp[i][j] = i;
            for (int k = 1; k < i; k++) {
                dp[i][j] = min(dp[i][j], max(dp[k-1][j-1], dp[i-k][j]) + 1);
            }
        }
    }
    return dp[N][K];
}

思路: O(K * logN)

我們可以改變一下求解的思路,求k個雞蛋在m步內可以測出多少層:
假設: dp[k][m] 表示k個雞蛋在m步內最多能測出的層數。
那么,問題可以轉化為當 k <= K 時,找一個最小的m,使得dp[k][m] <= N。

我們來考慮下求解dp[k][m]的策略:
假設我們有k個雞蛋第m步時,在第X層扔雞蛋。這時候,會有兩種結果,雞蛋碎了,或者沒碎。
如果雞蛋沒碎,我們接下來會在更高的樓層扔,最多能確定 X + dp[k][m-1] 層的結果;
如果雞蛋碎了,我們接下來會在更低的樓層扔,最多能確定 Y + dp[k-1][m-1] 層的結果 (假設在第X層上還有Y層)。
因此,這次扔雞蛋,我們最多能測出 dp[k-1][m-1] (摔碎時能確定的層數) + dp[k][m-1] (沒摔碎時能確定的層數) + 1 (本層) 層的結果。
另外,我們知道一個雞蛋一次只能測一層,沒有雞蛋一層都不能測出來。
因此我們可以列出完整的遞推式:
dp[k][0] = 0
dp[1][m] = m (m > 0)
dp[k][m] = dp[k-1][m-1] + dp[k][m-1] + 1 (k > 0, m>0)

代碼:

// NOTE: 第一維和第二維換了下位置
int superEggDrop(int K, int N) {
    int dp[N+2][K+2];
    memset(dp, 0, sizeof(dp));
    dp[0][0] = 0;
    for (int m = 1; m <= N; m++) {
        dp[m][0] = 0;
        for (int k = 1; k <= K; k++) {
            dp[m][k] = dp[m-1][k] + dp[m-1][k-1] + 1;
            if (dp[m][k] >= N) {
                return m;
            }
        }
    }
    return N;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM