排列組合問題
這篇隨筆講解信息學奧林匹克競賽比較常見的一種題型——排列組合問題。閱讀並理解本篇隨筆要求讀者具有不低於高中一年級的數學素養,並且了解信息學中遞歸、深搜算法的基本實現方式,能理解一般的遞歸程序。
上課!!
1、排列和組合的定義
(1)排列的定義
從\(n\)個不同元素中,選出\(m\)個元素按照一定順序排成一列,叫做從\(n\)個不同元素中取出\(m\)個元素的一個排列。
(2)排列數的定義
從\(n\)個元素中選出\(m\)個元素的所有排列的個數,叫做從\(n\)個不同元素中取出\(m\)個元素的排列數。
(3)全排列的定義
當\(n=m\)時所有的排列情況叫做全排列。
(4)組合的定義
從\(n\)個不同元素中,選出\(m\)個元素並成一組,叫做從\(n\)個不同元素中取出\(m\)個元素的一個組合。
(5)組合數的定義
從\(n\)個元素中選出\(m\)個元素的所有組合的個數,叫做從\(n\)個不同元素中取出\(m\)個元素的組合數。
(6)排列&組合的區別
通俗地說,組合不分順序,而排列分順序,也就是說,對於數列\(1,2\),有以下兩種排列:\(1,2\)和\(2,1\),但是僅有一種組合\(1,2\)或\(2,1\).
2、排列&組合的公式
(1)關於排列的公式
從\(n\)個不同元素中,選出\(m\)個元素的排列數,數學表示為:\(A_n^m\).
計算公式如下:
(2)關於組合的公式
從\(n\)個不同元素中,選出\(m\)個元素的組合數,數學表示為:\(C_n^m\).
計算公式如下:
(3)關於全排列的公式
某個數列的全排列數\(f(n)\),計算公式如下:
3、全排列的求法
例題:生成全排列(深搜基礎題)
給定\(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;
}