數學高手看過來!!!

    分三部分:一、問題由來;二、個人分析;三、數學問題。如果您直接奔着解決數學問題來的,可以直接跳到第三部分。但爲了更好的理解,建議都看一遍,或許有其他更好的解題思路。
    一、問題由來

    昨晚羣裏一網友發表一組合問題,一開始以爲他要從1~160正整數中取9個出來,這樣的組合有多少種。他一問有這麼多組合嗎?重新看了一遍問題,又以爲是把1~160分成9組,這樣的組合有多少種。 (⊙﹏⊙)b 後跟他交流後才明白他的意思。


    用通俗一點的語言重新表達下問題:從1~160正整數中取9個數(數值可一樣),分別給9個人,使9個人的數值總和爲160。請問這樣的組合有多少個?


    二、個人分析    
    第一反應,數據那麼大,肯定是寫個程序去處理。
    首先排除153以上的數字,使用遍歷法,把1~152從小到大依次給前8個人。如果前8個人的數值總和sum小於160,第9個人的數值肯定是160-sum,這樣的組合便爲一種組合。
    在寫程序的時候,使用的是遞歸算法。爲了加快處理,每個人提取數字時的循環遍歷最大值imax做了一個限制。因爲每個人都會提取一個數字,最小值爲1,所以第x個人的imax值等於160減去前x-1個數值總和,再減去後面剩餘人的個數,即imax = 160 – sum(x-1) – (9 – x)。這樣就不用再去遍歷總和超過160的數字了(可以看出,這些組合數比我們要算的大的多)。下面是用的C語言寫的,下標是從0開始。

#include <stdio.h>
#include <stdlib.h>

#define MAX_VALUE 160
#define MAX_GROUP 9
double count = 0;
int a[MAX_GROUP];

void ResultDisplay()
{
	int i;

	printf("%12.0f: ", count);
	for(i=0;i<MAX_GROUP;i++)
		printf("%3d ",a[i]);
	printf("\n");
}
int Combination(int sum, int n)
{
	int i=1;

	if( sum>=MAX_VALUE)
		return -1;
	if(n == MAX_GROUP - 1){
		a[n] = MAX_VALUE - sum;
		count++;
		ResultDisplay();
		return 0;
	}
	for(i=1; i<=MAX_VALUE - sum - (MAX_GROUP - 1 - n);i++){
		a[n] = i;
		Combination(sum+i, n+1);
	}
}

int main(int argc, char **argv) 
{
	Combination(0,0);

	system("pause");
	return (0);
}

    用我的本本運行了一分鐘,結果如下:


    組合數已達到3萬多,但前5個人還是1。這裏打印耗了很多時間,如果去掉打印,結果會快N倍。去掉後運行過半小時(運行起來後,本本的風扇一直處於高速轉動的狀態,擔心古董受不鳥,所以運行幾分就暫停一小會),通過監視看到組合數達到300多億,但第1個人的數還是1,第2個人的數字也沒超過2(忘了截圖,印象中還是1)。看到這樣真正的天文數字,沒敢再繼續運行下去了,但由此推斷出組合數肯定超1000億。
    PS:昨晚在羣裏回覆說組合數肯定超1000億。一位羣管理員表現出一副很不屑和被我忽悠的樣子(“1000億?別瞎我,我輸讀的少”)。一向認爲羣管理的話會比較穩重,再說這是一個技術羣。你可以懷疑我說的,我們可以一起討論驗證,但你說這樣諷刺和挑釁的話,對於我來說,最好的反駁就是拿出證據放羣裏給他看。在打印處加了個條件中斷,從99999999990(差10就1000億)開始打印。運行了近兩個小時的時間,結果終於出來了,當時已經晚上1點了,立馬編輯好文字,給他回覆了過去。


    1000億,第1個人還是1,零頭可能都還沒達到呢。。。 
    以上爲插曲,迴歸正題。此數學問題提出的時候,最長運行時間僅半小時,即300多億。當時就想有沒有一個公式,能直接用公式把組合數算出來。爲了直觀點,就在Excel裏做了幾個簡單點的組合,看能否找到規律和思路。如:5分爲2,5分爲3,5分爲4,8分爲4。

 

 

    一開始從後面開始找規律,最後一個不用看,就看最後兩個,發現如果前面所有的數之和固定,那最後兩個數的和也是固定的(這是廢話),那組合數爲最後兩個數之和,再減1。這應該很好理解,假設最後兩個數之和爲y,那組合分別爲(1, y-1), (2, y-2), … , (y-1,1),共y-1個。再倒數第三位數在遞增的時候,y在遞減。看上去很有規律,但仔細去找的時候卻發現都是一些等差數列的疊加啊。
    換個方向吧,從前面開始找找看。如上圖,8分爲4中,把第1人給不同數時的組合數給列出來了。把它的公式寫出來後,發現僅適合8分爲4這個組合方式,其他的都算不出正確答案。
    這時,想到高中時統計學的統計方法(好像是統計學吧?),就是找到第n個與n-1個的關係。

【以爲文本內容含很多博客編輯器無法顯示的公式,都將使用圖片】


#include <stdio.h>
#include <stdlib.h>

#define MAX_VALUE 100
#define MAX_GROUP 7

double KCombination(int m, int n)
{
	double sum=0;
	int i=0;

	if(m<n){
		printf("Error!\n");
		return (-1);
	}
	if(m==n)
		return (1);
	if(n==2)
		return (m-1);
	if(n==1)
		return (1);

	for(i=m-1;i>=n-1;i--){
		sum += KCombination(i,n-1);
	}
	return sum;
}

int main(int argc, char **argv) 
{
	printf("the number of the method of combination is: %.0f\n",KCombination(MAX_VALUE,MAX_GROUP));

	system("pause");
	return(0);
}






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