這篇隨筆講解信息學奧林匹克競賽比較常見的一種題型——排列組合問題。閱讀並理解本篇隨筆要求讀者具備不低於高中一年級的數學素養,而且瞭解信息學中遞歸、深搜算法的基本實現方式,能理解通常的遞歸程序。php
從\(n\)個不一樣元素中,選出\(m\)個元素按照必定順序排成一列,叫作從\(n\)個不一樣元素中取出\(m\)個元素的一個排列。c++
從\(n\)個元素中選出\(m\)個元素的全部排列的個數,叫作從\(n\)個不一樣元素中取出\(m\)個元素的排列數。算法
當\(n=m\)時全部的排列狀況叫作全排列。數組
從\(n\)個不一樣元素中,選出\(m\)個元素併成一組,叫作從\(n\)個不一樣元素中取出\(m\)個元素的一個組合。spa
從\(n\)個元素中選出\(m\)個元素的全部組合的個數,叫作從\(n\)個不一樣元素中取出\(m\)個元素的組合數。3d
通俗地說,組合不分順序,而排列分順序,也就是說,對於數列\(1,2\),有如下兩種排列:\(1,2\)和\(2,1\),可是僅有一種組合\(1,2\)或\(2,1\).code
從\(n\)個不一樣元素中,選出\(m\)個元素的排列數,數學表示爲:\(A_n^m\).blog
計算公式以下:
\[ A_n^m=n(n-1)(n-2)\cdots(n-m+1)=\frac{n!}{(n-m)!} \]遞歸
從\(n\)個不一樣元素中,選出\(m\)個元素的組合數,數學表示爲:\(C_n^m\).get
計算公式以下:
\[ C_n^m=\frac{A_n^m}{m!}=\frac{n!}{m!(n-m)!} \]
某個數列的全排列數\(f(n)\),計算公式以下:
\[ f(n)=n! \]
例題:生成全排列(深搜基礎題)
給定\(n\),生成\(1-n\)的全排列。
咱們考慮用遞歸來解決全排列問題:
遞歸出口是當x==n+1地時候,絕對不能僅僅等於n!!
咱們的遞歸部分使用標記數組和數列數組實現,具體實現方法能夠參照下圖:
咱們遞歸的過程大致是如下的思路:
三個數位可能出現1-3每一個數,因此咱們使用遞歸算法求解的時候,先圈定這一個值,而後繼續下搜,遍歷完這「一條鏈」的時候,就上回一個數位看看還有沒有其餘選擇,這樣就保證瞭解不重不漏。
例題代碼:
#include<bits/stdc++.h> using namespace std; int n,a[20],v[20]; void dfs(int x) { if(x==n+1) { for(int i=1;i<n;i++) printf("%d ",a[i]); printf("%d\n",a[n]); return; } for(int i=1;i<=n;i++) { if(v[i]==0) { a[x]=i; v[i]=1; dfs(x+1); v[i]=0; } } } int main() { scanf("%d",&n); dfs(1); return 0; }