求一算法能够快速算组合数C(m,n).

wengzhong 2003-05-05 02:31:07
象以下的程序中的算法不符合要求.

#include<iostream>
#include<iomanip>
using namespace std;
double fn(double m)
{
double result=1;
while(m!=1)
{
result*=m;
--m;
}
return result;
}

double ShowDown(double m,double n)
{
double temp=m;
double result=1;
if(n==0)
{
return 0;
}
while(m!=temp-n)
{
result*=m;
--m;
}
return result/fn(n);
}
int main()
{
double m,n;
cin>>m>>n;
while(m+n!=0)
{
cout<<setprecision(10)<<ShowDown(m,n)<<endl;
cin>>m>>n;
}
return 0;
}

...全文
1201 点赞 收藏 16
写回复
16 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
Elivon 2003-05-15
不过,我给出的乘法版本(上面),速度还可以,
比帖主的快得多
回复
Elivon 2003-05-15
int combination(int m,int n)//m为下标,n为上标
{
if(m<0||n<0||m<n) return -1;
//数据不符合要求,返回错误信息
int result=0,temp1;
stack com;
com.push(m,n);
while(com.head)
{
com.pop(m,n);
temp1=m-n;
n=n<temp1?n:temp1;//C(m,n)=C(m,m-n)
if(n==0)
{
result+=1;
if(result<0) return MAX;
}
else if(n==1)
{
result+=m;
if (result<0) return MAX;
}
else
{
m--;
com.push(m,n);
com.push(m,--n);
}
}
return result;
}
原则:
一.化为整数加法
C(m,n)=C(m-1,n)+C(m-1,n-1)
若出现n==0||n==m,值为1
若出现n=1,值为m
二.C(m,n)=C(m,m-n)
三.用m—代替m-1
实践证明:这种方法是行不通的,很慢,
因为加法操作太多,如算C(30,15),每次最多加30,加到什么时候才是个头?
回复
Elivon 2003-05-15
int combination(int m,int n)//m为下标,n为上标
{
if(m<0||n<0||m<n) return -1;
//数据不符合要求,返回错误信息
n=n<(m-n)?n:m-n;//C(m,n)=C(m,m-n)
if(n==0) return 1;
int result=m;//C(m,1);
for(int i=2,j=result-1;i<=n;i++,j--)
{
result=result*j/i;//得到C(m,i)
}
return result;
}
回复
zzpdhr 2003-05-07
动态规划
回复
glasswing 2003-05-07
Elivon(Elivon):
>化为整数加法
>C(m,n)=C(m-1,n)+C(m-1,n-1)

这个方法是正解。乘法和加法速度可是差一个数量级。
递归层次的问题,楼主可以试一试,m还没到100 C(m, n)老早已经是天文数字了。

当然追求速度的场合递归不是好方法,不过改成循环也不是难事

另:大家没听过杨辉三角吗?

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
...
回复
bbsfwys 2003-05-07
以上的程序,有些同学比较好 ,但有些就不行了。yuxue198248的同学,你想的方法我同意,
但是你给的程序就有好多好多的错误呀??
以下是我根据你的想法改编的 只供参考::
#include<stdio.h>
void main()
{int m,n,s,a;
scanf("%d,%d",&m,&n);
a=s(n)/(s(m)*s(n-m));
printf("%d",a);
}
int s(int n)
{if(n==0)
return 1;
else
return(n*s(n-1));
}
回复
wengzhong 2003-05-07
楼上的也不能解决这个问题
没有考虑递归的极限问题!!
如果m是2的31次方,你试一试!!
递归本身是有限制的,递归层数超过时就不行了.大概1W多层.

这个题目本身看着是不难的,但实际上呢??
有几个人考虑全面了呢??
这个题目总是出现在初级的语法书上作为练习的,大家就以那中老眼光来看这个问题了.
对!
在数不是很大情况下,无所谓了,但是一旦超过这个范围呢??/
有谁想过呢??
报着的还是那种老的思路,
"不就个递归吗""简单".说这个的人肯定不在少数,也就这样没有什么人来看我的问题.
也许我该换个题目才能吸引更多的人来看看,来想想.这个"简单的问题".
这个问题的本质就是,怎么快速算大数的组合数.
回复
Elivon 2003-05-06
化为整数加法
C(m,n)=C(m-1,n)+C(m-1,n-1)

int ShowDown(int m,int n)
{
//1.整型的运算速度比浮点型要快的多


if(m<n) {cerr<<"error\n";exit(0);}
else
return ShowDown1(m,min(m,m-n));
//2.利用C(m,n) == C(m, m-n)的原理
}
int ShowDown(int m,int n)
{
if(m==n||n==0)return 1;
else if(n==1) return m;
else
return ShowDown(m-1,n)+ShowDown(m-1,n-1);
}
回复
wengzhong 2003-05-06
我要的是时间上的快,不是结构上的简单,
公式就是那个公式,但是从程序的结构上如何优化程序,使得程序运行的更快.
你们可以自己测试一下你们的那些程序,看看求结果最大是1-->2的31次方的所有数得用多少时间.
回复
yuxue198248 2003-05-06
我认为在数学上有两个组合公式可以用
C(M N)=P(M N)/P(M M)
P(M N)=N!/(N-M)!
c(m n)=n!/m!*(n-m)!
可以用
main()
{int m n a;
scanf(%d%d,m,n);
a=sss(n)/(sss(m)*sss(n-m));

int sss(int n)
{if(n==1)return 1
else
return(n*sss(n-1))
你看如何
简单吗









回复
boxban 2003-05-06
组合数C(m,n)总是整数,因此,计算过程中应该一致的使用整型变量,而不是double。
整型的运算速度比浮点型要快的多。
下面是一个简单的实现,但只能计算较小的数:(

另外,利用C(m,n) == C(m, m-n)的原理,又一个小小的优化。


#include <iostream>
#include <iomanip>
#include <assert.h>

using namespace std;

inline long x(int base, int loops)//caculate: base*(base-1)*(base-2)*...*(base-loops+1)
{
assert(base > 0 && loops > 0);
long ret = base;
while(--loops){
ret *= --base;
}

return ret;
}

long ShowDown(int m, int n)
{
assert(n >= 0 && m >= n);
if(m - n < n) n = m - n;
if(n == 0) return 0;

return (x(m, n)/x(n, n));
}


void main()
{
int m,n;

cin>>m>>n;
while(m+n!=0)
{
cout<<ShowDown(m,n)<<endl;
cin>>m>>n;
}
return ;
}
回复
hyflying 2003-05-06
组合数好像没有其他公式可算啊
去问问数学系的?
回复
eduhf_123 2003-05-06
关注
回复
wengzhong 2003-05-05
速度尽可能的快,上边的程序超时,能怎么快就怎么写.
回复
wengzhong 2003-05-05
输出的结果最大是2的31次方.
0<=n<=m; 1<=m;
回复
fenghuibing 2003-05-05
你想怎么写啊
回复
发动态
发帖子
C语言
创建于2007-09-28

6.3w+

社区成员

C语言相关问题讨论
申请成为版主
社区公告
暂无公告