引言
在开始论述之前,我想请大家先看下这几个问题:
- 有 \(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