元旦大放送之求组合数(直接相乘、递归函数、质因数分解)

输入m与n,m>=n,求出组合数的值
组合数的计算虽说简单,但也不乏有些陷阱,这主要是因为语言中的数据类型在表示范围上是有限的。还有中间结果溢出的现象。

思路一
分母是从n的阶乘,分子m乘到m-n+1,直接相乘分母必须从1开始,这样才能保证分子除以分母不出现小数,为了避免分子一开过大,从m-n+1开始往上乘,
虽然能一定程度上减小,可是还有可能在中间过程溢出。

include<stdio.h>

int main()
{
	int isum=1;
	int m,n,k;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		isum=1;
		for(k=1;k<=n;k++)
		{
			isum=(isum*(m-n+k))/k;
		}
			printf("%d\n",isum);
	}

}

用递归函数的写法就是利用组合数的性质
Cm n=Cm n−1+Cm−1 n−1
当n=0,结果是1,当m=n,结果是1,当m=1,结果是1;
这种是一步步加出来了的结果,中间过程不可能溢出,和斐波那契数列有点像,不过运算的速度太慢

include <stdio.h>

long long combine(int m,int n)
{
	if(m==n) return 1;
	else if(n==0) return 1;
	else if(m==1) return 1;
	else return combine(m-1,n-1)+combine(m-1,n);
	
} 



int main()
{
	int n,m;
	while((scanf("%d %d",&m,&n))!=EOF)
	{
		if(n>m/2) n=m-n;
		printf("%lld\n",combine(m,n));	
	}
}

第三种就是分解质因数,将分子分母的乘积写成质因数乘积,用数组储存指数,最后指数对应相减,剩下来的质因数相乘,
虽然对每个数提取质因数比较麻烦,但考虑到数非常小,分解的时间并不长,而且也不会出现溢出的情况,所以还是比较实用的方法

include <stdio.h>

#include <string.h>
//对正整数x进行质因数分解,质因数从小到大存在array[]数组中
int a[100];
int b[100];
int c[100];

void divide_1(int n)
{
	for(int i = 2; i * i <= n; i++)
	{
        while(n % i == 0)
		{ 
			a[i]++;
            n /= i;
    	}
}
if(n != 1){
    a[n]++;
}
}
void divide_2(int n)
{
	for(int i = 2; i * i <= n; i++)
	{
        while(n % i == 0)
		{ 
			b[i]++;
            n /= i;
    	}
	}
	if(n != 1)
	{
    	b[n]++;
	}
	
}


int main()
{
	int n,m;
	while((scanf("%d %d",&m,&n))!=EOF)
	{
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(c,0,sizeof(c));
		if(n>m/2) n=m-n;
		long long result=1;
		for(int i=m;i>=m-n+1;i--)
		{
			divide_1(i);
		}	
		for(int i=n;i>1;i--)
		{
			divide_2(i);
		}
		for(int i=2;i<50;i++)
		{
			c[i]=a[i]-b[i];
		}
		
		
		
		
		
		
		for(int i=2;i<50;i++)
		{
			if(c[i])
			{
				for(int j=0;j<c[i];j++)
				{
					result*=i;
				}
			}
		}
		printf("%lld\n",result);
	}
}
posted @ 2021-01-03 17:20  empty_thought  阅读(430)  评论(0)    收藏  举报