首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

在兑现组合数计算的时候要防止溢出

2013-03-27 
在实现组合数计算的时候要防止溢出1. 在计算组合数C(N, M)的时候如果利用公式n!/(m!*(n-m)!)的话,很可能会

在实现组合数计算的时候要防止溢出

1. 在计算组合数C(N, M)的时候如果利用公式n!/(m!*(n-m)!)的话,很可能会溢出。

    因为对于阶乘,13!已经超过了int能表示的范围,而且也会很快超过long long的表示范围。


2. 如果按照定义先计算分子,再计算分母,再相除的话也会溢出。


3. 最保险的计算方式如下:

分子:N*(N-1)*...*(N-M+2)(N-M+1)

分母:M*(M-1)*...*2*1


从后往前计算,先计算(N-M+1)/1=x1,再计算(N-M+2)*x1/2=x2,再计算(N-M+3)*x2/3,这样能防止溢出,代码如下:(这样计算能够保证每次的计算结果都是整数,因为每次的计算结果就是一个组合数)

当然如果本来组合数的大小就超过long long能表示的范围,那下面的代码也不行了。


#include <iostream>#include <iomanip>#include <cmath>#define PI 3.1415927using namespace std;//avoid use fac to calculate c(n,m)//fac will overflowlong long C(int N, int M) {long long sum = 1;for(int i=1;i<=M; i++) {sum=sum*(N-M+i)/i;}return sum;}//C(N, M)*(M个元素错排的总数)long long func(int N, int M) {long long num[51]={0};num[0]=1;//0个元素错排,即全部排对了,只有1种可能num[1]=0;num[2]=1;for(int i=3; i<=M; i++) {num[i]=(i-1)*(num[i-1]+num[i-2]);}return C(N,M)*num[M];}int main(){ int n;while(cin >> n) {if(n==0) break;long long sum = 0;for(int i=0; i<=n/2; i++) {//0,1 to n/2 错排 是符合要求的sum+=func(n,i);}cout << sum << endl;}return 0;}

上面的代码来源于HDUOJ2068题,属于排列组合+错排的综合。

热点排行