面試題-雙蛋問題(動態規劃)

肺炎疫情期間,在B站上看了李永樂老師關於雙蛋問題的視頻,剛好我最近寫了一篇關於動態規劃的文章,這裡我們試著使用動態規劃的思想簡單分析下這個問題。

一、問題描述

有一座100層的樓,有一個雞蛋,在低樓層的時候將雞蛋扔下不會碎,但是高樓層扔下會碎。存在一個臨界樓層從該樓層之上拋下來,雞蛋一定會碎。現在有N個雞蛋可以做檢查(雞蛋沒碎可以重複使用,但是碎了就不能使用了),問最少幾次(M)能夠找到這個臨界樓層。

二、嘗試

1)假設N=1,為了確保雞蛋不會碎,只能從第一層開始往上扔,直到雞蛋碎了為止,最差M=100

2)假設雞蛋有無限多,可以使用二分法來解決這個問題,即在第50層往下扔,如果雞蛋碎了就在25層繼續扔,如果沒碎的話,在75層往下扔。依次類推,直到找到為止。2^M>=100,m約等於6.64

如果N=2的情況下,最好需要多少次才能試出M?

1)假設第一個雞蛋每隔十層扔一次,10、20、30。。。100,等雞蛋碎著之後從再從區間內開始嘗試,如果在第100層碎了的話就是91-99,這樣就可以試出臨界樓層了。

臨界樓層出現在100層碎掉的話最壞的情況就是先扔10次(100/10=10)然後在91、92、93.。。99層向下扔,M=10+9=19。臨界樓層出現在10層碎掉的話最壞的情況就是先扔1次(10/10=1),然後在1、2、3。。。9層向下扔要10次,M=1+9=10

當然我們可以通過擴大、減小第一次扔雞蛋相隔樓層的數可以減少第二次扔雞蛋的次數,但是這種情況計算出的結果也並不一定就是最優解,所以我們可以引入動態規劃的思量來解決這個問題。

三、動態規劃

假設有t層樓和n個雞蛋,我們要如何計算出這個問題呢?

設M(t,n)為在從t層樓,n個蛋的情況下需要拋投的最少次數,假設在k層樓進行拋投,會產生兩種情況:

如果雞蛋碎了,那麼我們需要繼續計算的就是M(k, n-1)(n-1是因為雞蛋碎了)

如果雞蛋沒碎,那麼我們需要繼續計算的就是M(t-k, n)

因為我們需要找到最壞的情況,所以我們需要去兩者中的最大值

因此我們可以得出,在k層扔下第一顆雞蛋Mk(t,n) = max(M(k-1, n-1), M(t-k, n)) + 1

k值可能為1-t次,因此想要找拋投的最少次數為M(t,n)= min(M1(t,n), M2(t,n), M3(t,n) ...... Mk(t,n))

在t=1或者n=1的時候,我們能夠清楚的計算出M(t,n),這就是該問題的邊界。

有了邊界和狀態轉移公式,我們就可以通過代碼實現這個問題

public static int getMin(int t, int n) {

int[][] dp = new int[t + 1][n + 1];

// 邊界處理,只有一個雞蛋,i層就要扔i次

for (int i = 1; i < t + 1; i++) {

dp[i][1] = i;

}

// 邊界處理,只有一層,不論雞蛋有幾個只要扔一次就可以

for (int j = 1; j < n + 1; j++) {

dp[1][j] = 1;

}

for (int i = 2; i < t + 1; i++) {

for (int j = 2; j < n + 1; j++) {

int min = Integer.MAX_VALUE;

for (int k = 1; k < i; k++) {

min = Math.min(min, Math.max(dp[i - k][j], dp[k - 1][j - 1]) + 1);

}

dp[i][j] = min;

}

}

return dp[t][n];

}


分享到:


相關文章: