poj 2249 Binomial Showdown(组合数 公式优化)

//  组合数学,开始了……

题目地址 : poj 2249 Binomial Showdown

Description

In how many ways can you choose k elements out of n elements, not taking order into account? 
Write a program to compute this number.

Input

The input will contain one or more test cases. 
Each test case consists of one line containing two integers n (n>=1) and k (0<=k<=n). 
Input is terminated by two zeroes for n and k.

Output

For each test case, print one line containing the required number. This number will always fit into an integer, i.e. it will be less than 2 31
Warning: Don't underestimate the problem. The result will fit into an integer - but if all intermediate results arising during the computation will also fit into an integer depends on your algorithm. The test cases will go to the limit. 

Sample Input

4 2
10 5
49 6
0 0

Sample Output

6
252
13983816

Source


/******************************

组合数公式的优化

普通的组合数公式:C(n,m) = n!/((n-m)!*m!) = (n * n-1 * n-2 * n-3 * n-4 * n-5 * n-6 * …… * n-m) / (m * m-1 * m-2 * m-3 * m-4 * m-5 * …… * 2 * 1)

优化 :将分子和分母 的因子分别存到一个数组中 nn[]  (分子)  mm[] (分母),双重循环遍历, 进行各个因子约分,因为 组合数为一个整数 ,即N % M = 0,

所以mm[] 的元素一定可以全部约分为1,然后只需将 mm[] 中的元素相乘就行了。。

******************************/

#include <iostream>
#include<string.h>
#include <stdio.h>
using namespace std;
const int N = 10000;
int nn[N],mm[N];
int gcd(int a,int b)//  求n,m 的最大公约数
{
    return (b==0)?a:gcd(b,a%b);
}
int main()
{
    int i,j,n,m,t,h,sum,temp;
    while(cin>>n>>m&&(n||m))//  程序结束条件是 n,m 中一个为0就行,用||,我开始用&& WA了好多次,要注意
    {
        t = h = 0;
        sum = 1;
        //cout<<gcd(m,n)<<endl;
        if(m>n-m)
            m = n-m;
        for(i = n-m+1;i<=n;i++)// 分子赋值
            nn[t++] = i;
        for(i = 1;i<=m;i++)//  分母赋值
            mm[h++] = i;
        for(i = 0;i<m;i++)
        {
            for(j = 0;j<m;j++)
            {
                temp = gcd(nn[i],mm[j]);//  约分
                nn[i] = nn[i]/temp;
                mm[j] = mm[j]/temp;
            }
        }
        for(i = 0;i<m;i++)
            sum*=nn[i];
        cout<<sum<<endl;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值