码迷,mamicode.com
首页 > 其他好文 > 详细

数学高手看过来!!!

时间:2015-04-11 20:52:37      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:数学   c   组合   和为定值   

    分三部分:一、问题由来;二、个人分析;三、数学问题。如果您直接奔着解决数学问题来的,可以直接跳到第三部分。但为了更好的理解,建议都看一遍,或许有其他更好的解题思路。
    一、问题由来

    昨晚群里一网友发表一组合问题,一开始以为他要从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);
}

技术分享

技术分享




数学高手看过来!!!

标签:数学   c   组合   和为定值   

原文地址:http://blog.csdn.net/a10615/article/details/44998647

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!