1. 程式人生 > >Google面試題-高樓扔雞蛋問題

Google面試題-高樓扔雞蛋問題

高樓扔雞蛋問題   這個問題很有名了  早幾年之前面試的時候都遇到過,但是當時也確實沒搞清楚怎麼做,後來也沒管了。今天網上偶然碰到,打算趁這個機會徹底搞清楚,就寫一篇博文吧。網上很多資料,但我感覺都不太易懂,每一步的推導是為什麼。所以我這裡只想寫一種比較簡單、比較完整的推演流程。

題目描述: (挑了一個比較嚴謹的描述。問題描述嚴謹很重要,不然會影響解題思路)
一幢 100 層的大樓,給你兩個雞蛋. 如果在第 n 層扔下雞蛋,雞蛋不碎,那麼從前 n-1 層扔雞蛋都不碎.
這兩隻雞蛋一模一樣,不碎的話可以扔無數次. 已知雞蛋在0層扔不會碎.
提出一個策略, 要保證能測出雞蛋恰好不會碎的樓層, 並使此策略在最壞情況下所扔次數最少

.

問題分析:

1)最壞情況下所扔次數最少,比較繞口。想表達的意思是,在不明確知道哪一層會碎的情況下,要找到一種策略,通過最少的試驗次數,得到臨界樓層(恰好不會碎的樓層)。不明確知道,就需要考慮最糟糕的情況,而且這種策略與其他策略相比是最糟糕的情況下,最少的試驗次數。

2)假設一種扔法:第一個雞蛋,從50樓扔下去。如果碎了,第二個雞蛋必須從1~49層逐層試驗。如果第i層為臨界層,且i≤49,這個時候,要試驗的總次數是1 +(i - 1)。因為必須保證在沒找到臨界樓層之前,雞蛋不能碎。如果沒碎,則第一個雞蛋可以接著從75層扔。因為即使這次碎了,還有個雞蛋,可以繼續逐層試驗。對第一個雞蛋的繼續從中間分,就比較合理。

3)假設到代數:如果第一枚雞蛋扔下去的層數為i,則碎了的情況,需要扔的總次數最糟糕的情況是1 + ( i - 1 );如果沒碎,剩下的兩個雞蛋都在,需要扔的次數一定為1 + 用兩枚雞蛋來解決剩下的100 - i層的次數(這個問題跟原題是一樣的,但是層數少了一些)。也就是 如果用f ( 100 )表示100層的最壞情況下的最少次數,那麼從第i層扔雞蛋的最糟糕的試驗次數是 1+ Max( i - 1, f ( 100 - i ) ),Max表示這兩者之間的最大值,是最最糟糕的情況了。  而 f ( 100 ) 就是對所有從1到100的所有i裡, 1+ Max( i - 1, f ( 100 - i ) )的值最小的那個。

4)迭代公式: f ( 100 ) = Min ( 1 + Max ( i - 1, f (100 - i ) ) ) .   其中Max是針對的 i-1、 f ( 100 - i ) 兩者 , 而Min是針對的所有的從1到100的i。

5)初始狀態: 如果有一層,從第一層扔下去,不管碎不碎,最糟糕的情況也只需要判斷一次。 即 f ( 1 ) = 1。而如題所述,第0層不會碎,則 不用扔也知道,即f(0) = 0。

6)最終結論:題目變成了分析一個迭代公式的值。翻譯成了計算機語言,剩下的就可以交給計算機了。不需要知道怎麼一步步算,這不應該是人乾的事。只需要知道已經變成了可以迴圈遞迴的算式,可以交給計算機就行了。

// 實現程式碼   <a target=_blank href="http://blog.csdn.net/lonelyrains">blog.csdn.net/lonelyrains</a>

#include <stdio.h>

// #define MAX((a),(b)) (a)>(b)?(a):(b)  //注意這裡也是常考的一點,應該寫成下面的形式
#define MAX(a,b) ((a)>(b)?(a):(b))

int fun ( int layer )
{
	if ( layer <= 0 )
	{
		return 0;
	}

	if ( layer == 1 )
	{
		return 1;
	}

	int min = layer; // 一棟layer層的大樓試驗次數肯定不可能超過layer次。
	int temp;
	for ( int i = 1; i <= layer; i++ )
	{
		temp = 1 + MAX(i-1, fun( layer - i ) );
		if( min > temp )
			min = temp;
	}

	return min;
}

int main()
{
	int layer = 19;
	printf("%d",fun(layer));
	return 0;
}

// 實現程式碼 <a target=_blank href="http://blog.csdn.net/lonelyrains">blog.csdn.net/lonelyrains</a>#include <stdio.h>// #define MAX((a),(b)) (a)>(b)?(a):(b) //注意這裡也是常考的一點,應該寫成下面的形式#define MAX(a,b) ((a)>(b)?(a):(b))int fun ( int layer ){if ( layer <= 0 ){return 0;}if ( layer == 1 ){return 1;}int min = layer; // 一棟layer層的大樓試驗次數肯定不可能超過layer次。int temp;for ( int i = 1; i <= layer; i++ ){temp = 1 + MAX(i-1, fun( layer - i ) );if( min > temp )min = temp;}return min;}int main(){int layer = 19;printf("%d",fun(layer));return 0;}用上面的程式碼測試了一下,給layer賦值19,即針對一棟19層的大樓來算最壞情況的最少次數,就要很長時間才能出結果了(果然18層是地獄)....    

7)其他擴充套件:

① 問題的解法不止這一種描述,而且不一定要交給計算機算,因為這樣遞迴算,計算機要累死了。可以優化到用很簡單的數列求和公式得到。關於怎麼來的,有兩種思路。可以參考下面的第二個參考連結給出的基於意義的理解,這是一種思路,但是比較難理解。另外一種,就是純粹的組合數學方法,將迭代公式轉換成通項公式,這個問題還沒找到有人這樣寫過,但是絕對可以有。

② 問題可以擴充套件為一棟n層的大樓,有m個雞蛋;甚至不止一棟,而是p棟。 不管怎麼樣擴充套件,問題都可以歸為找迭代公式。這個思路就是動態規劃的精髓。

8)參考連結: