排列與排列數、組合與組合數


排列與排列數、組合與組合數


排列與排列數

  1. \(n\)個不同元素中,任取\(m(m \le n)\)個元素,按照一定的順序排成一列,叫做從\(n\)個不同元素中取出\(m\)個元素的一種排列。

    • 注意:排列的元素完全相同,順序也完全相同
  2. 公式:\(P^m_n=\frac{n!}{(n-m)!}\)

    • 如何理解這個公式:

      1. 例1:三名同學,成績前兩名有多少種可能性?

        1. 第一名:3種可能性
        2. 第二名:(3-1)種可能性
        3. 根據乘法原理,共有\(3*(3-1)\)種可能性
      2. 例2:七名同學,成績前五名有多少種可能性?

        • 由例一,易知有\(7*(7-1)*(7-2)*...*(7-5+1)\)
      3. 由例1例2進行進一步推導,用\(m,n\)代替具體的數字,可得

        • \(n(n-1)(n-2)(n-3)...(n-m+1)\)
      4. 整理可得,

        \(n(n-1)(n-2)(n-3)...(n-m+1)=\frac{1*2*3*...(n-2)(n-1)n}{1*2*3*...(n-m-1)(n-m)}\)

        (即乘上\(\frac{1*2*3*...(n-m-1)(n-m)}{1*2*3*...(n-m-1)(n-m)}\),目的是得到完整的、從1開始的可以化為階乘形式的數)

      5. 繼續整理,得到\(P^m_n=\frac{n!}{(n-m)!}\)

      6. 但是通過第3步得到的式子,其實是不需要階乘的

        從大的數字開始往小乘,乘小的數字那么多個


組合與組合數

  1. \(n\)個不同元素中,任取\(m(m \le n)\)個元素並成一組,叫做從\(n\)個不同元素中取出\(m\)個元素的一個組合。

  2. 記號:\(C(n,k)\)\(\binom{n}{k}\)

  3. 公式:\(\binom{n}{k}=\frac{P(n,k)}{P(k,k)}\)

  4. 推導公式:\(\binom{n}{k}=\frac{\frac{k!}{(k-n)!}}{\frac{n!}{(n-n)!}}=\frac{k!}{n!(k-n)!}\)

  5. 用更常用的\(m,n\)來表示組合數公式,就得到了\(\binom{m}{n}=\frac{n!}{m!(n-m)!}\)

  6. 理解公式:

    1. 觀察可知,其實組合數就是在排列數公式上除以一個\(m!\)\(P(k,k)\)其實就等於\(k!\)

    2. 思考一下:組合數與排列數的區別是組合數不要求順序相同,所以如果按照排列數去求組合數,會出現一定數目的重復

    3. 打表找規律():

      1. 四選三(即m=3,n=4):

        1. 排列數:共\(P^3_4=\frac{4!}{(4-3)!}=\frac{4*3*2*1}{1}=24\)

          ABC,ABD,ACB,ACD,ADB,ADC,
          BAC,BAD,BCA,BCD,BDA,BDC,
          CAB,CAD,CBA,CBD,CDA,CDB,
          DAB,DAC,DBA,DBC,DCA,DCB;

        2. 觀察,剔除重復項

          ABC,ABD,ACD,BCD \(4\)

        3. 找規律:保留了\(\frac{24}{6}\)種,即保留了\(\frac{4*3*2*1}{3*2*1}\)種,即\(C^m_n=\frac{P(m,n)}{m!}\)

        4. 嗯現在就假裝推完了吧()

      從大的數字開始往小乘,乘“小的數字那么多”個,再除以“小的數字開始往小乘,乘小的數字那么多個”


拓展公式

  1. \(C^m_n=C^{n-m}_n\)

    其實就是反選,從五個里面取出四個的組合數就相當於從五個里面取一個(取哪四個等同於不取哪一個)

  2. \(C^{m-1}_n+C^m_n=C^m_{n+1}\)

    這個似乎在\(m\)\(n\)比較大的時候可以有效避免爆空間

  3. \(C^0_n+C^1_n+......+C^n_n=2^n\)

  4. \(C^r_r+C^r_{r+1}+......+C^r_n=C^{r+1}_{n+1}\)

  5. \(\displaystyle\sum_{i=0}^kC^i_nC^{k-i}_{m}=C^k_{m+n}\)

這三個公式還沒悟等悟了在補充

代碼實現

  1. 定義式

    int C(int m,int n){
        //這里用longlong是因為第6行乘完之后極有可能暫時超過了int能表示的范圍
    	long long result = 1;
    	
    	for(int i = 0;i<n;i++){
    		result *= (m-i);
    	}
    	for(int i = 2;i<=n;i++){
    		result /= i;
    	}
    	return (int)result;
    }
    

    非常容易想到

  2. 遞歸版組合數求法

    int C(int m,int n){
    	if(m == n) return 1;
    	if(n == 1) return m;
    	return C(m-1,n)+C(m-1,n-1);
    } 
    

    根據拓展公式(2)寫的,優點是非常好寫(手和腦子只能懶一個),缺點是慢......

    這張圖是以C(7,3)為例畫的圖(不得不說!這網站!實在是太強了)

    一眼就能看見相當多的重復運算

  3. 遞推版組合數求法

    int C(int m,int n){
    	int c[n+1][m+1];
    	for(int i = 1;i<=m;i++){
    		c[1][i] = i;
    	}
    	for(int i = 2;i<=n;i++){
    		c[i][i] = 1;
    	}
    	for(int i = 2;i<n;i++){
    		for(int j = i+1;j<m;j++){
    			c[i][j] = c[i-1][j-1] + c[i][j-1];
    		}
    	}
    	for(int i = n+1;i<=m;i++){
    		c[n][i] = c[n-1][i-1] + c[n][i-1];
    	}
    	return c[n][m];
    }
    

    既然\(C(m,n)\)\(m,n\)都有關系,那么不妨開一個n行m列的二維數組(m行n列也行,自己調整一下)

    看上圖的所有的葉子節點,都是\(m=n\)或者\(n=1\)

    \(m=n\)\(C(m,n)=1\)

    \(n=1\)\(C(m,n)=m\)

    因此,代碼的第3~8行開出了如下表的一個二維數組

    1 2 3 4 5 6 7
    1 1 2 3 4 5 6 7
    2 1
    3 1

    接着,根據拓展公式二,我們可以知道這個二維數組的每一項等於其左側值和左上值的和

    並且第m列(即上表中的第7列)除了最后一行都沒有必要填上(填上也行)

    所以代碼的第9~13行將二維數組填充到了如下表所示的程度

    1 2 3 4 5 6 7
    1 1 2 3 4 5 6 7
    2 1 3 6 10 15
    3 1

    然后第14~17行填完了最后一行

    最后返回值即可


    這是以C(36,24)為例的耗時(再大遞推還是秒出,但遞歸我可能真的等不了了)


如何通俗的解釋排列公式和組合公式的含義? - 浣熊數學的回答 - 知乎


免責聲明!

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



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