【POJ 2249】 Binomial Showdown 組合數學 排列組合計算

我是一隻計算雞發表於2019-01-18

組合(combination),數學的重要概念之一。從n個不同元素中每次取出m個不同元素(0≤m≤n),不管其順序合成一組,稱為從n個元素中不重複地選取m個元素的一個組合。所有這樣的組合的總數稱為組合數,這個組合數的計算公式為

或者

簡單的說就是從n個數中每次取m個元素,一共有多少種不同的取法。

tips:如果用第一個公式計算組合時,可能因為階乘過大而導致乘法溢位。所以我們選用第二個公式來計算。在進行分子乘法的同時,與分母約分,因為組合數是個整數,所以當分母不為1時,gcd(分子的某一項,分母的某一項)!=1,所以將分子和分母的對應項同時除以gcd,只至分母為1。

POJ2249題目大意:從n個數中取m個不同的元素,一共用多少種取法,很明顯就是一個組合數。下面給出程式碼

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=2000+7;
int p[maxn];    //分子
int q[maxn];    //分母
int gcd(int a,int b)
{
    int c;
    while(b){      //gcd(a,b)=gcd(b,a%b)   gcd(a,0)=a;  輾轉相除法的兩個核心公式
        c=b;
        b=a%b;
        a=c;
    }
    return a;
}
int main()
{
    int m,n;
    while(scanf("%d %d",&n,&m)==2&&(m||n)){
        if(n==0)printf("1\n");
        else {
            if(m>n-m) m=n-m;
            int temp=n;
            for(int i=1;i<=m;i++){
                p[i]=temp--;
                q[i]=i;
            }
            for(int i=1;i<=m;i++){
                for(int j=1;j<=m;j++){
                    int temp=gcd(p[i],q[j]);
                    if(temp!=1){
                        p[i]=p[i]/temp;
                        q[j]=q[j]/temp;
                    }
                    if(p[i]==1)break;  //當分子的某一項已經為1 即不能再約分
                }
            }
        int ans=1;
        for(int i=1;i<=m;i++)
        ans=ans*p[i];
        printf("%d\n",ans);
    }
    }
    return 0;
}

相關文章