組合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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM