元旦大放送之求组合数(直接相乘、递归函数、质因数分解)
输入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);
}
}

浙公网安备 33010602011771号