1. 程式人生 > >整型陣列處理演算法(十三)求出用1,2,5這三個數不同個數組合的和為100的組合個數(華為校園招聘題)

整型陣列處理演算法(十三)求出用1,2,5這三個數不同個數組合的和為100的組合個數(華為校園招聘題)

寫一個程式, 要求功能:求出用1,2,5這三個數不同個數組合的和為100的組合個數。

如:100個1是一個組合,5個1加19個5是一個組合。。。。 請用C++語言寫。

       下面用2中方法來實現它。

       從中我們可以引申出來,這其實,是一種方法,在我們解決問題的時候,如果進度緊,效能要求也不高,可以選擇最簡單的方式來實現它,當功能實現後,可以在花時間來優化,完善。同時,對新的演算法也可以用以前簡單的方法來驗證。這只是一個簡單的組合題。實際專案中,遇到的問題比這個複雜很多。那怎麼辦?首先要進行分解。然後對分解後的問題,都有哪些要求進行定級,然後在進度和效能中間做取捨。比如新建一個網站,你就考慮伺服器要支援千萬級的併發量,這個級別就沒有定準。其實新建一個網站,能支援十萬併發就是比較高的目標了。這是什麼意思呢,就是說在網站上線後,網站併發十萬是需要一段時間的。而這段時間足夠你來解決併發量的問題。

        這是一方面,另一方面就是市場在不斷的變化,技術也在不斷地更新。所以,要跟上市場的節奏,技術的價值才可以得以體現。比如你用1,2年的時間做了一個網站,結果當你推向市場的時候,發現市場上類似的網站很多了。已經沒有你的發展空間。那這樣,即使你網站的伺服器可以支援千萬級,有何用?

最容易想到的演算法是:

設x是1的個數,y是2的個數,z是5的個數,number是組合數

注意到0<=x<=100,0<=y<=50,0<=z=20,所以可以程式設計為:

number=0;
for (x=0; x<=100; x++)
	for (y=0; y<=50; y++)
		for (z=0; z<=20; z++)
			if ((x+2*y+5*z)==100)
				number++;
cout<<number<<endl;

上面這個程式一共要迴圈100*50*20次,效率實在是太低了

事實上,這個題目是一道明顯的數學問題,而不是單純的程式設計問題。

我的解法如下:

因為x+2y+5z=100

所以x+2y=100-5z,且z<=20 x<=100 y<=50

所以(x+2y)<=100,且(x+5z)是偶數

對z作迴圈,求x的可能值如下:

z=0, x=100, 98, 96, … 0

z=1, x=95, 93, …, 1

z=2, x=90, 88, …, 0

z=3, x=85, 83, …, 1

z=4, x=80, 78, …, 0

……

z=19, x=5, 3, 1

z=20, x=0

因此,組合總數為100以內的偶數+95以內的奇數+90以內的偶數+…+5以內的奇數+1,

即為: (51+48)+(46+43)+(41+38)+(36+33)+(31+28)+(26+23)+(21+18)+(16+13)+(11+8)+(6+3)+1

某個偶數m以內的偶數個數(包括0)可以表示為m/2+1=(m+2)/2

某個奇數m以內的奇數個數也可以表示為(m+2)/2

所以,求總的組合次數可以程式設計為:

number=0;
for (int m=0;m<=100;m+=5)
{
	number+=(m+2)/2;
}
cout<<number<<endl;

這個程式,只需要迴圈21次, 兩個變數,就可以得到答案,比上面的那個程式高效了許多倍——只是因為作了一些簡單的數學分析。

這再一次證明了:計算機程式=資料結構+演算法,而且演算法是程式的靈魂,對任何工程問題,當用軟體來實現時,必須選取滿足當前的資源限制,使用者需求限制,開發時間限制等種種限制條件下的最優演算法。而絕不能一拿到手,就立刻用最容易想到的演算法編出一個程式了事——這不是一個專業的研發人員的行為。

那麼,那種最容易想到的演算法就完全沒有用嗎?不,這種演算法正好可以用來驗證新演算法的正確性,在除錯階段,這非常有用。在很多大公司,例如微軟,都採用了這種方法:在除錯階段,對一些重要的需要好的演算法來實現的程式,而這種好的演算法又比較複雜時,同時用容易想到的演算法來驗證這段程式,如果兩種演算法得出的結果不一致(而最容易想到的演算法保證是正確的),那麼說明優化的演算法出了問題,需要修改。

可以舉例表示為:

#ifdef DEBUG
int simple();
#end if
int optimize();
……
in a function:
{
	result=optimize();
	ASSERT(result==simple());
}


這樣,在除錯階段,如果簡單演算法和優化演算法的結果不一致,就會打出斷言。同時,在程式的釋出版本,卻不會包含笨重的simple()函式。——任何大型工程軟體都需要預先設計良好的除錯手段,而這裡提到的就是一種有用的方法。