“汽水三換一”問題的兩種問法及巧妙解答

此題今年我在包括360在內的三家公司的筆試面試中遇到過,總結了此題的兩種問法及巧妙解決方案,方便大家應對招聘或者當個智力題開動下思維也好。

問法一:三個空瓶換一瓶汽水,某班買了30瓶汽水,要保證每人喝一瓶汽水,最多可以供給多少名同學?
問法二:三個空瓶換一瓶汽水,某班有30名同學,要保證每人喝一瓶汽水,最少需要買多少瓶水?

此題在我小學三年級的時候就在某“智力”書上看過,讓我印象這麼深的原因是因爲它有一個巧妙的思想:比如剩兩個空瓶子了,你可以再像老闆賒一瓶汽水,喝完可以把三個空瓶子給老闆(相當於一瓶汽水),所以剩兩個空瓶子的時候也可以喝到一瓶汽水!

現在我們來看相對簡單的問法一,因爲它是正着問的,邏輯推理上很順,比如我們買了30瓶汽水,首先可以供給30名同學,剩下30個空瓶可以換10瓶汽水可以供給同學總數爲30+10名,接下來10個空瓶可以換3瓶汽水供給總數爲30+10+3名,最後剩了4個空瓶可以再供給1名同學,最後剩下兩個空瓶,根據開始的“思想”還可以供給1名同學一共可以供給30+10+3+1+1 = 45名.

用程序實現這個算法也很簡單,供大家參考:
public class SanHuanYi {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		int init_bottle_num = 30;//初始汽水的數量
		int person_num = 0;//能供給同學的數量
		
		person_num = getAllBottleNum(init_bottle_num);
		System.out.println(person_num);
		
	}
	static int getAllBottleNum(int bottle_num){
		if(bottle_num <= 0)
			return 0;
		int all_num = bottle_num;//all_num最終數量
		while(bottle_num >= 3){
			int temp = bottle_num / 3;
			all_num += temp;
			bottle_num = temp + bottle_num % 3;
		}
		all_num += bottle_num == 2 ? 1: 0;//剩兩瓶總數量就加1
		return all_num;
	}

}
問法一還有更巧妙的解法,先賣個關子,最後再說,也許您看完問法二自己也能想出來。

問法一還算比較簡單,我筆試面試遇到的都是問法二,這個問法似乎就得逆着想了,我最初的想法是比如供給30個同學,似乎買20瓶,再根據"三換一"原則感覺上總數跟30差不多,再在20附近取數比如19,21...最終找到一個需要汽水最小的數。當然這是一個正確的解法。但在筆試中不可能花費大量的時間算一個小題,也不可能在面試中用“拙劣”的方法吸引到面試官。所以介紹一個“分組”算法來解決這個問題。
比如需要供給30名同學,根據“N換一”問題把同學分成“30/N”組,比如此題N=3,我們就把人分成30/3 = 10組,我們假設按順序供給他們,第一組我們需要供給3瓶汽水,等第一組喝完我們手裏有了3個空瓶子正好可以換1瓶汽水,所以我們供給第二組的時候只要再買兩瓶汽水就夠了!當第二組喝完,我們又有了3個空瓶子,依次類推。。。直到最後一組,我們需要買3+ 2 *(10-1) = 21瓶汽水,但是最後剩下3個空瓶可以,所以我們可以少買一瓶就是20瓶就夠了(也就是說該第30名同學喝汽水時手裏有了兩個空瓶,根據最開始的“思想”可以再換一瓶)。但如果一共31名同學,分組完還剩一人,這時我們正好把最後一組喝完剩下的3個空瓶子給他,結果就是21瓶;如果一共32名同學,只好再多買一瓶了,總數爲22瓶。總結:先對總人數分Sum/3個組,然後可以利用公式 3+2*(Sum/3-1)獲得汽水總瓶數,如果分組後沒有餘下人就用總瓶數減1,如果餘下1個人,總瓶數不變;如果餘下2個人;總瓶數加1
我們最後可以寫個簡單的程序模擬這個過程:
public class SanHuanYi {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		int person_num = 30;//需要供給的人數
		int all_bottle_num = getLeastBottle(person_num);
		System.out.println(all_bottle_num);
		
	}

	static int getLeastBottle(int person_num){
		
		if(person_num <= 0)
			return 0;
		if(person_num > 0 && person_num < 3)
			return person_num;
		int sum = 0;		
		int group_num = person_num / 3;//能夠分的組數
		int yushu = person_num % 3;//分組完,剩餘的人
		sum = 3 + (group_num-1) * 2;
		if(yushu == 0){
			sum--;
		}else if(yushu == 1){
			
		}else{
			sum++;
		}
		
		return sum;
	}
}

好了,我們現在回頭看看問法一的巧妙解法:買了30瓶汽水,先可以供給30名同學,剩了30個空瓶子,我們還是利用那個“思想”,找15個同學每人分兩個空瓶子,讓他們自己去找老闆,那麼他們都能喝到汽水,所以直接用30+15 = 45就完了!


==================================================================================================

  作者:nash_  歡迎轉載,與人分享是進步的源泉!

  轉載請保留原文地址http://blog.csdn.net/nash_/article/details/8235632

===================================================================================================

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章