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 d, int e) { int **f=new int *[d+1]; int i,j,k; for(i=0;i<=d;i++) f[i]=new int[e+1]; for(i=0;i<=d;i++) f[i][1]=i; for(i=0;i<=e;i++) f[0][e]=0; for(i=1;i<=e;i++) { for(j=1;j<=d;j++) { int tmp; int min_test=0x7FFFFFFF; for(k=1;k<=j;k++) { tmp=f[j-k][i]+1>f[k-1][i-1]+1?f[j-k][i]+1:f[k-1][i-1]+1; if(tmp<min_test) min_test=tmp; } f[j][i]=min_test; } } int result=f[d][e]; for(i=0;i<=d;i++) delete[]f[i]; delete[]f; return result; }?
總結
以上是生活随笔為你收集整理的100层楼2个鸡蛋,如何得知鸡蛋能承受几层的撞击的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 纯CSS画三角形(带边框)
- 下一篇: RT-thread 设备驱动组件之IIC