组合c(n,m)的计算方法

方法一:暴力求解

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
long long C(int m, int n) {
    int k = 1;// 相当于 C(m,n)   
    long long ans=1;
    while(k<=n)
    {
        ans=((m-k+1)*ans)/k;
        k++;    
    }     
    return ans;
}
int main()
{
    printf("%lld", C(10 ,5));
}

方法二:杨辉三角打表

原理:C(n,m)=C(n-1,m-1)+C(n-1,m)

#include<iostream>
using namespace std;
int n,m;
long long c[10005];
int main()
{
    cin>>n>>m;
    m=min(m,n-m);//因为C[n][m]=C[n][n-m],所以m可以取m和n-m中小的那一个,以节省时间。
    c[0]=1;
    for (int i=1;i<=n;i++)
    {
        for (int j=m;j>=1;j--)
        {
            c[j]=c[j]+c[j-1];
        }
    }
    cout<<c[m];
}

方法三:分解质因数

求解思路:

 

 

 

1. 筛法求出范围内的所有质数。
2. 通过 C(n, m) = n! / m! / (n - m)! 这个公式求出每个质因子的次数。 n! 中p的次数是 n / p + n / p^2 + n / p^3 + ...
3. 用高精度乘法将所有质因子相乘。

代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int prime[1000],cnt=0,rat[1000];
bool p[1000];
void findprime(int n)//欧拉筛来找素数
{
    for (int i = 2; i <= n; i++)
    {
        if (!p[i])
            prime[cnt++] = i;
        for (int j = 0; j < cnt; j++)
        {
            if (i*prime[j] > n)break;
            p[i*prime[j]] = true;
            if (i%prime[j] == 0)break;
        }
    }
}
int rate(int n, int p)//分解质因数,求得每个质因数在n!中的出现个数
{
    int res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}
vector<int>mul(vector<int>a, int b)//高精度乘法*低精度数字(此时的a一直是反着的,所以最后反着输出)
{
    vector<int>answer;
    int t=0;//进位数 
    for (int i = 0; i < a.size(); i++)
    {
        t += a[i] * b;
        answer.push_back(t % 10);
        t /= 10;
    }
    while (t)//处理最高位的数字,防止最高位的数字大于9
    {
        answer.push_back(t % 10);
        t /= 10;
    }
    return answer;
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    findprime(n);
    for (int i = 0; i < cnt; i++)
        rat[i] = rate(n, prime[i]) - rate(m, prime[i]) - rate(n - m, prime[i]);//计算每个质因数的幂的次数
    
    vector<int>fin;
    fin.push_back(1);
    for (int i = 0; i < cnt; i++)//所有质因数的迭代
        for (int j = 0; j < rat[i]; j++)// rat[i]是每个质因数在合数中的次数,所以这里是将每个质因数乘rat[i]次
            fin = mul(fin, prime[i]);

    for (int i = fin.size() - 1; i >= 0; i--)
        printf("%d", fin[i]);
}

代码步骤讲解

1.欧拉筛来找素数

如果对欧拉筛不熟悉,点击此处查看。

 

2.分解质因数,求得每个质因数在n!中的出现个数

求N!中素因子p的个数,也就是N!中p的幂次

公式为:cnt=[n/p]+[n/p^2]+[n/p^3]+...+[n/p^k];

例如:N=12,p=2

12/2=6,表示1~12中有6个数是2的倍数,即2,4,6,8,10,12

12/2^2=6/2=3,表示1~12中有3个数是4的倍数,即4,8,12,它们能在提供2的基础上多提供一个2

12/2^3=3/2=1,表示1~12中有1个数是8的倍数,即12,它能在提供两个2的基础上又多提供一个2

代码就是

int rate(int n, int p)//分解质因数,求得每个质因数在n!的出现个数
{
    int res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}

效果:

例如求c(5,3),则通过代码首先要计算5的质因数:2 3 5;

之后分别计算每个质因数在n中的出现个数:rate(2)=3;rate(3)=1;rate(5)=1;而5!=5 * 4 * 3 * 2 *1;其中将合数转换为素数,则2出现的个数就是rate(2)的值:3次(一个4,一个2,相当于3个2),3、5的出现次数各为1

而每个质因数在n!的出现的个数就是每个质因数在n!中对应的幂数

 

3.使用C(n, m) = n! / m! / (n - m)! 这个公式求出每个质因子的次数

我们上一步计算出了每个质因数在n!中的幂数,而类比就能求出在m!、(n-m)!中的幂数,而C(n, m) = n! / m! / (n - m)! 这个式子的值就是各个质因子在n!中的幂数-在m!中的幂数-在(n-m)!中的幂数,即

for (int i = 0; i < cnt; i++)
        rat[i] = rate(n, prime[i]) - rate(m, prime[i]) - rate(n - m, prime[i]);//计算每个质因数的幂的次数

 

4.高精度乘法计算结果

至此,我们将C(n, m)的值转换为了多个质因子的若干幂次方的乘积,我们通过高精度*低精度来计算(大数运算知识:请点击此处了解)

vector<int>mul(vector<int>a, int b)//高精度乘法*低精度数字(此时的a一直是反着的,所以最后反着输出)
{
    vector<int>answer;
    int t=0;//进位数 
    for (int i = 0; i < a.size(); i++)
    {
        t += a[i] * b;
        answer.push_back(t % 10);
        t /= 10;
    }
    while (t)//处理最高位的数字,防止最高位的数字大于9
    {
        answer.push_back(t % 10);
        t /= 10;
    }
    return answer;
}

在大数的乘法计算中,首先是要把原来的大数求逆后再从前往后计算,最后再将答案逆序输出,但是此时看似vector<int>a未求逆就直接乘了,最后还是逆序输出???

其实这里的原因是vector<int>a的初始化其实是1,这里的1要理解成已经是求逆后的(单个数字求逆还是原数)

例如:初始a中是1,令b=5;开始1 *5 =5;vector<int>p中是5

再调用mul函数,就是5 *5 =25;此时vector<int>p中是52

再调用mul函数,就是25 *5 =125;此时vector<int>p中是521

最后逆序输出就是125


 

for (int i = 0; i < cnt; i++)//所有质因数的迭代
        for (int j = 0; j < rat[i]; j++)// rat[i]是每个质因数在合数中的次数,所以这里是将每个质因数乘rat[i]次
            fin = mul(fin, prime[i]);

最后将所有的质因子都乘rat[i]遍,再去乘别的质因子,最后将结果逆序输出就是C(n, m)的值

 

参考:

https://blog.csdn.net/apcsgf/article/details/37648833?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1

https://blog.csdn.net/lzyws739307453/article/details/99715833?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1

https://blog.csdn.net/weixin_33895016/article/details/94615900

posted @ 2020-04-30 21:53  Jason66661010  阅读(3368)  评论(0编辑  收藏  举报