引言
在開始論述之前,我想請大家先看下這幾個問題:
- 有 \(2n\) 個人排成一行進入劇場。入場費 5 元。其中只有 \(n\) 個人有一張 5 元鈔票,另外 \(n\) 人只有 10 元鈔票,劇院無其它鈔票,問有多少中方法使得只要有 10 元的人買票,售票處就有 5 元的鈔票找零?
- 一位大城市的律師在她住所以北 \(n\) 個街區和以東 \(n\) 個街區處工作。每天她走 \(2n\) 個街區去上班。如果他從不穿越(但可以碰到)從家到辦公室的對角線,那麼有多少條可能的道路?
- 在圓上選擇 \(2n\) 個點,將這些點成對連線起來使得所得到的 \(n\) 條線段不相交的方法數?
- 對角線不相交的情況下,將一個凸多邊形區域分成三角形區域的方法數?
- 一個棧(無窮大)的進棧序列為 \(1,2,3, \cdots ,n\) 有多少個不同的出棧序列?
- \(n\) 個結點可夠造多少個不同的二叉樹?
- \(n\) 個不同的數依次進棧,求不同的出棧結果的種數?
- \(n\) 個 \(+1\) 和 \(n\) 個 \(-1\) 構成 \(2n\) 項 \(a_1,a_2, \cdots ,a_{2n}\) ,其部分和滿足 \(a_1+a_2+ \cdots +a_k \geq 0(k=1,2,3, \cdots ,2n)\) 對與 \(n\) 該數列為?
它們中我相信大家或多或少接觸過一些,在解決這些問題的方法中,Catalan數就是一種很便利的組合數學方法。
定義與性質
首先來看看Wiki對 Catalan
數的定義:
卡特蘭數(Catalan number)是組合數學中一個重要的計數數列,在很多看似毫不相關地方都能見到它的身影(目前最早證明卡特蘭數的是清朝數學家明安圖,所以Catalan數也被稱作“明安圖數”或“明安圖-卡塔蘭數”)
卡塔蘭數的一般項公式為:
其對應的序列為:
\(C_0\) | \(C_1\) | \(C_2\) | \(C_3\) | \(C_4\) | \(C_5\) | \(C_6\) | ... |
---|---|---|---|---|---|---|---|
1 | 1 | 2 | 5 | 14 | 42 | 132 | ... |
Catalan數的漸近增長為:
它的含義是當n → ∞時,左式除以右式的商趨向於1。(這可以用\(n!\) 的斯特靈公式來證明。)
所有的奇卡塔蘭數\(C_n\) 都滿足$ n = 2^k - 1$ 所有其他的卡塔蘭數都是偶數。
而且
\(C_n = \int_0^4x^n\frac{1}{2\pi}\sqrt{4/\pi - 1}\)
應用
帶限制條件的路徑總數
首先我們來看一個問題:
在一個平面直角座標系中,只能往右或往上走一個單位長度,問有多少種不同的路徑可以從左下角 (1,1) 走到右上角 (n,n),並且要求路徑不能經過直線 y=x 上方的點,下圖中的路徑都是合法的(圖片來源 Wikipedia)
如果沒有限制條件,那麼從左下角走到右上角一共有 \(2n\) 步,有 \(n\) 步是往右,另外 n 步是往上,那麼路徑方案數就是 \(2n\) 步中選擇 n 步往右,一共有 \(\begin{pmatrix}2n\\n\end{pmatrix}\) (即 \(C^n_{2n}\))種方案
那麼我們考慮一下這裡面有多少種方案是不合法的
首先對於每一種不合法的方案,它的路徑一定與 y=x+1 有交。我們找到它與 y=x+1 的第一個交點,然後將這個點後面部分的路徑關於 y=x+1 做一個對稱。由於原來路徑到達 (n,n),新的對稱之後的路徑就會到達 \((n−1,n+1)\)。這樣我們把每一種不合法方案都對應到了一條從 (1,1) 到 $(n−1,n+1) $ 的路徑,現在再來看是否每一條這樣的路徑都能對應到一種不合法方案,如果是,那麼這就建立了一個一一對映的關係,也就是它們的方案總數相同。這是肯定的,因為每一條這樣的路徑必定與 y=x+1 有交,那麼對稱回去,就得到一條不合法方案
由於從$ (1,1)$ 到 \((n−1,n+1)\) 的路徑有$ \begin{pmatrix}n−1+n+1\n−1\end{pmatrix} $條,那麼合法的方案就是
我們把這個方案數記為$ C_n$,這就是著名的 Catalan 數
我們來看看它的前幾項(\(n\) 從 0 開始)
1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190
括號序列計數
再來看一個問題:有多少種不同的長度為 n 的括號序列?
首先一個括號序列是指 (), ()(), (())() 這樣的由括號組成的序列,並且沒有左右括號無法匹配的情況
我們可以將長度為 2n 的括號序列對映成剛剛所說的路徑:首先對於左括號,那麼就向右走一個單位長度,對於右括號,那麼就向上走一個單位長度,由於括號序列合法,那麼每次向右走的次數不會少於向上的次數,也就是這條路徑不會在 y=x 之上。再考慮每一條這樣的路徑,也能夠對應到一種合法的括號序列,因此,長度為 2n 的括號序列的方案數就是 \(C_n\)。
出棧順序
現在來考慮你有 n 個元素(元素之間是沒有區別的)和一個棧,每次可以將一個元素入棧,或者將棧頂元素彈出,問有多少種可能的操作序列,這可以將問題對應成括號序列,入棧為左括號,出棧為右括號,因此方案數也是 \(C_n\)
排隊問題
現在有 2n 個人,他們身高互不相同,他們要成兩排,每一排有 n 個人,並且滿足每一排必須是從矮到高,且後一排的人要比前一排對應的人要高,問有多少種排法
我們考慮先把這些人從矮到高排成一排,那麼現在來分配哪個人在前,哪個人在後,例如有 6 個人,身高是 1, 2, 3, 4, 5, 6
那麼我們用 1 表示這個人應該在後排,0 表示這個人應該在前排,例如說 100110 表示兩排分別是 2, 3, 6 和 1, 4, 5 這是不合法的
那麼合法方案應該是怎麼樣的呢?後排要比前排對應的人高,也就是說 0 的出現次數在每一個地方都不應該小於 1,這恰恰又是一個括號序列,因此,方案仍然是 Catalan 數
二叉樹計數
現在你需要統計有多少種不同的 n 個結點的二叉樹
圖上的是 3 個結點的二叉樹,一共有 5 種方案
樸素的想法是由於二叉樹是遞迴定義的,可以考慮使用遞推方法
我們可以用 \(f_n\) 表示有 n 個結點的二叉樹的方案數(空樹算一種,即 \(f_0=0\)),那麼列舉子樹大小可以得到方程
如果直接計算,你需要 $O(n^2) $的時間
現在我們換一個角度來想,對這棵二叉樹進行遍歷,並且考慮一個括號序列,當第一次遇到這個結點的時候,在括號序列末尾新增一個左括號,在從左子樹回到這個結點的時候,在括號序列中新增一個右括號,這樣,將每一種不同的二叉樹都對應到了一種不同的括號序列,同樣對於每一種不同的括號序列都可以找到對應的一種不同的二叉樹,因此,有 \(n\) 個結點的二叉樹的數量也是 \(C_n\)
ACM訓練題
例題洛谷 P1044 棧
題目大意:入棧順序為 \(1,2,\ldots ,n\) ,求所有可能的出棧順序的總數。
#include <iostream>
using namespace std;
int n;
long long f[25];
int main() {
f[0] = 1;
cin >> n;
for (int i = 1; i <= n; i++) f[i] = f[i - 1] * (4 * i - 2) / (i + 1);
//這裡用的是常見公式2
cout << f[n] << endl;
return 0;
}
待補。。。
參考
Miskcoo's Space關於Catalan數的證明:http://blog.miskcoo.com/2015/07/catalan-nuber