zoukankan      html  css  js  c++  java
  • 求组合数的C++实现

    #include <iostream>
    using namespace std;

    int com(int n,int r)
    {
    int i,j,s=1;
    if(n-r<r) r=n-r;
    for(i=0,j=1;i<r;i++){
    s
    *=(n-i);
    while(j<=r && s%j==0){
    s
    /=j;
    j
    ++;
    }
    }
    return s;
    }

    int main()
    {
    int n,m;
    while(cin>>n>>m){
    cout
    <<com(n,m)<<endl;
    }
    return 0;
    }

    上面的代码只适合较小的n,经测试,当n=33 时,对于所有小于等于 n 的 m均能计算出值。n>33时,仅对于较小的m适用。

    在网上找了找,学会了计算组合数的新方法

    http://hi.baidu.com/sulipol/blog/item/9a83278990ba1b98a5c2723d.html

    下面的代码则利用了 素数唯一分解定理 

    N=P1^e1*P2^e2*...*Pr^er 其中Pi为素数因子,ei是正整数。

    n是素数当且仅当 r=1 且 e1=1

    组合数计算算法流程:1,素数打表  2,幂整数拆分  3,快速幂模

    蓝色字为引用:

    有一个小函数,求n!中含数x的几次方

    int getx(int n,int x)//计算n!中质因子2的出现次数
    {
        if(n==0)
            return 0;
        return n/x+get2(n/x);
    }

    int getx(int n,int x)//非递归写法
    {
    ans=0;
    while(n)
    {
       ans+=n/x;
       n/=x;
    }
    return ans;
    }

    算法解释:

    60/5=12;12/5=2;所以可以肯定60!中含有5^14

    第一次的60/5 我们找到了5^1倍数的所有数,

    第二次12/5 相当于(60/5)/2==60/5^2,集计算60中含有5^2倍数的个数

    …………以此类推

    注意:由于n/(x^i-1)计算已经包含了n/x^i的n/(x^i-1)部分,所以n/x^i仅算n/x^i

    个x,而非(n/x^i)*i个x,

    2.拆分后对分式进行降幂运算

    x1[i]-=(x2[i]+x3[i]) 可以证明x1[i]>=0

    证明:由于C(n,m)结果必然为整数,即n!%((n-m)!*m!)==0

    所以n!为(n-m)!*m!的整数倍,即pi^x1i%(pi^x2i*pi^x3i)==0

    即pi^(x1[i]-x2[i]-x3[i])为整数

    x1[i]-x2[i]-x3[i]>=0

    证毕

    #include <iostream>
    #include
    <cstring>
    #include
    <cmath>
    #define SET(a) memset(a,0,sizeof(a))
    #define M 150000
    #define N 1000001
    #define MOD 20110413
    /*
    C(n,m)=n! / ((n-m!)*m!)
    n!=2^x1*3^x2*5^x3***pi^xi
    */

    int p[M];
    int x1[M];//n!
    int x2[M];//(n-m)!
    int x3[M];//m!

    int pn; //numbers of the prime number
    using namespace std;

    int getprime(){
    int i,j,k=1;
    p[
    0]=2;
    for (i=3;i<M;i+=2){
    int flag=1;
    for(j=2;j<=sqrt(i);j++){
    if(i%j==0) {
    flag
    =0;
    break;
    }
    }
    if(flag==1) p[k++]=i;
    }
    return k;
    }

    int getx(int n,int p){
    int x=0;
    while (n){
    x
    +=n/p;
    n
    /=p;
    }
    return x;
    }

    int div(int n,int x[]){
    int i;
    for (i=0;i<pn && n>=p[i];i++){
    x[i]
    =getx(n,p[i]);
    }
    return i;
    }

    __int64 b_pow(
    int *arr,int n)
    {
    int i;
    __int64 res
    =1,a,b,d;
    for(i=0;i<n;i++){
    if(arr[i]){
    a
    =p[i];
    b
    =arr[i];
    d
    =1;
    while(b){
    if(b%2) d=(a*d) % MOD;
    a
    =(a*a) % MOD;
    b
    >>=1;
    }
    res
    =(res*d) % MOD;
    }
    }
    return res;
    }

    __int64 C(
    int n,int m){
    int len,i;
    len
    =div(n,x1);
    div(n
    -m,x2);
    div(m,x3);
    for (i=0;i<M;i++)
    x1[i]
    -=(x2[i]+x3[i]);
    return b_pow(x1,len);
    }

    int main() {
    int n,m;
    __int64 ans;
    SET(p);
    pn
    =getprime();
    while(cin>>n>>m){
    SET(x1);
    SET(x2);
    SET(x3);
    ans
    =C(n,m);
    cout
    <<ans<<endl;
    }
    return 0;
    }
  • 相关阅读:
    linux下的进程
    进程间通讯
    const关键字
    关于嵌入式web服务器
    指针
    内存管理(malloc和free的用法)
    关于read和fread
    C库的制作
    C语言考试
    docker 配置阿里云镜像加速
  • 原文地址:https://www.cnblogs.com/bl4nk/p/2023038.html
Copyright © 2011-2022 走看看