谷歌“扔雞蛋問題”

問題:

? ? 假設有2個雞蛋和100層樓,將雞蛋從第n層扔下,雞蛋沒有碎,將雞蛋從n+1層扔下,雞蛋碎了,那么n層就是雞蛋不會摔碎的臨界點。

問:如何用最少的次數(shù)測試出最壞的情況下雞蛋不會摔破的臨界點。

思路一:二分法

? ? 對于均勻列表的查找,我們首先想到的是二分法。在本題中,首先第一個雞蛋從五十層扔,因為只有兩個雞蛋,假如第一個碎了,第二個不能在使用二分法,所以得從第一層開始一層層實驗。那么最壞的情況需要50次。

思路二:開平方

? ? 為了使次數(shù)最少,那么兩個雞蛋在最壞的情況下試的次數(shù)數(shù)應該盡可能接近因為是兩個雞蛋,很容易想到開平方100 = 10 * 10,第一個雞蛋從10,20···,這樣開始扔,那么最壞的情況是10,20,···,90,91,···,99,100共18次

思路三:逆推法

? ? 在思路二中,假設第一個雞蛋在第十層沒有碎,那么問題就變成了2個雞蛋從90層樓向下扔,求測出臨界點所需的最少次數(shù),按照開平方的思路,應該對90開平方,依次類推,可以看出思路二也不是最優(yōu)解。為了找出最優(yōu)解,我們采用逆推法:

  • 第一步:假定x是最優(yōu)解,然后找出第一次雞蛋應該扔下的樓層
  • 第二步:假設我們從x+1層開始嘗試,那么最壞的情況是,雞蛋x+1層碎了,第二個雞蛋需要從第一層一直試到x層,共試了x+1次,這與最優(yōu)解x次矛盾。
  • 第三步:假設我們從x-1層開始嘗試,那么最壞的情況是,雞蛋x-1層碎了,第二個雞蛋需要從第一層一直試到x-2層,共試了x-1次,這也與最優(yōu)解x次矛盾。
  • 第四步:從二,三步來看,應該從x層開始扔,假設層雞蛋碎了,最壞嘗試次數(shù)為x,和假設相符合。
  • 第五步:假設x層雞蛋沒碎,那么前x層被排除了,那么接下來問題轉(zhuǎn)換成了“從100-x層上扔2個雞蛋,用最少的次數(shù)測試出最壞的情況下雞蛋不會摔破的臨界點”,而該問題的最優(yōu)解是x-1,且應該從x+(x-1)層,開始測試。
  • 第六步:以第五步類推,假設第一個雞蛋始終沒有碎,最后該開始測試的樓層是x+(x-1)+(x-2)+....+1,因為我們有100層樓,可以得到下面公式:


  • 第七步:因為x是正整數(shù),所以x=14。即最優(yōu)解是14。
思路四:動態(tài)規(guī)劃

? ? 假設從x層開始測試時,以f(100)表示100層中從x層開始扔雞蛋測試出臨界點所需最少次數(shù),有以下情況:

  • 雞蛋在x層碎了,最壞還需測試100-x次
  • 雞蛋在x層未碎,最壞還需要f(x-1)次

? ? 也就是說從x層開始測試最壞的情況是max(100-x,f(x-1))有以下公式:

  • 狀態(tài)轉(zhuǎn)移方程


  • 邊界


? ? 根據(jù)上面公式編寫java代碼

private static int f() {
    int floor = 100;
    int[] temp = new int[floor];
    temp[0] = 1;
    temp[1] = 2;
    for (int i = 2; i < floor; i++) {
        temp[i] = 1 + Math.max(i - 1, temp[0]);
        for (int j = 2; j <= i; j++)
            temp[i] = Math.min(1 + Math.max(i - j, temp[j - 1]), temp[i]);
    }
    return temp[floor - 1];
}

擴展

? ? 假設有n個雞蛋和m層樓,求是雞蛋不會摔碎的臨界點。同樣假設從x層開始測試時,以f(m,n)表示m層中從x層開始扔雞蛋測試出臨界點所需最少次數(shù),有以下情況:

  • 雞蛋在x層碎了,最壞還需要f(m-x,n-1)次

  • 雞蛋在x層未碎,最壞還需要f(x-1,n)次
    ? ? 也就是說從x層開始測試最壞的情況是max(f(m-x,n-1),f(x-1,n)),有以下公式:

  • 狀態(tài)轉(zhuǎn)移方程


  • 邊界


? ? 根據(jù)上面公式編寫java代碼

private static int f(int floor, int eggs) {
    int[][] temp = new int[floor+1][eggs+1];
    for (int i = 1; i <= floor; i++) {
        for (int j = 1; j <= eggs; j++) {
            if (1 == i) {
                //f(1,n) = 1
                temp[i][j] = 1;
            } else if (1 == j) {
                //f(m,1) = m
                temp[i][j] = i;
            } else {
                //f(m,n)=min(1+max(f(m-x,n-1),f(x-1,n)))
                temp[i][j] = 1 + Math.max(temp[i - 2][j - 1], temp[1][j]);
                for (int k = 2; k <= i; k++) {
                    temp[i][j] = Math.min(temp[i][j], 1 + Math.max(temp[i - k][j - 1], temp[k - 1][j]));
                }
            }
        }
    }
    return temp[floor][eggs];
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容