特别鸣谢
概念
情境导入
一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列?
可以形象化地转化为括号问题,更好理解,进栈是(,出栈是),下面为n=3的全部序列
- 首先,我们设 f(n)=序列个数为n的出栈序列种数。
- 同时假定,从开始到栈第一次出到空为止,这段过程中第一个出栈的序数是k。特别地,如果栈直到整个过程结束时才空,则k=n。
- 首次出空之前第一个出栈的序数k将1 ~ n的序列分成两个序列:其中一个是1 ~ k-1,序列个数为k-1;另外一个是k+1 ~ n,序列个数是n-k。
- 此时,我们若把k视为确定一个序数,那么根据乘法原理,f(n)的问题就等价于——序列个数为k-1的出栈序列种数乘以序列个数为n - k的出栈序列种数(一种递归的思想),即选择k这个序数的f(n)=f(k-1)×f(n-k)。
- 而k可以选1到n,所以再根据加法原理,将k取不同值的序列种数相加,得到的总序列种数为:
抽象分析
经过上面的分析我们抽象出了一类函数:
这就是卡特兰数的递推式
我们把f换成C表示,有如下公式
递推公式2是我们要用代码实现的部分,方便多次询问查询
如果仅仅查询一次,可以离线计算组合数使用通项公式1或者性质
性质推导见模型分析1
C0 = 1,
C1 = 1, C2 = 2, C3 = 5, C4 = 14, C5 = 42,
C6 = 132, C7 = 429, C8 = 1430, C9 = 4862, C10 = 16796,
C11 = 58786, C12 = 208012, C13 = 742900, C14 = 2674440, C15 = 9694845,
C16 = 35357670, C17 = 129644790, C18 = 477638700, C19 = 1767263190, C20 = 6564120420, ...
代码实现
//函数功能: 计算Catalan的第n项
//函数参数: n为项数
//返回值: 第n个Catalan数
int N=20;
int h[N];
int Catalan(int n)
{
if(n<=1) return 1;
h[0] = h[1] = 1; //h(0)和h(1)
for(int i=2;i<=n;++i) //依次计算h(2),h(3)...h(n)
{
h[i] = 0;
for(int j = 0; j < i; j++) //根据递归式计算 h(i)= h(0)*h(i-1)+h(1)*h(i-2) + ... + h(i-1)h(0)
h[i] += (h[j] * h[i-1-j]);
}
int result = h[n]; //保存结果
return result;
}
模型分析
我们要想办法把相关问题转化为括号问题(出栈问题)
1. 01序列
给出一个n,要求一个长度为2n的01序列,使得序列的任意前缀中1的个数不少于0的个数, 有多少个不同的01序列?
以下为长度为6的序列:
111000 101100 101010 110010 110100
其本质就是括号问题/入栈问题:
1. 因为对于每一个数来说,必须进栈一次、出栈一次。我们把进栈设为状态‘1’,出栈设为状态‘0’。n个数的所有状态对应n个1和n个0组成的2n位二进制数。
2. 由于等待入栈的操作数按照1‥n的顺序排列、入栈的操作数b大于等于出栈的操作数a(a≤b),因此输出序列的总数目=由左而右扫描由n个1和n个0组成的2n位二进制数,1的累计数不小于0的累计数的方案种数。
操作及性质推导如下
其解等于第n个Catalan数。
2. 标准Young表
将 1~2n 填入一个 的方格表中,使得每一行自左而右、每一列自上而下都是严格增的。
当 n=3 时,有5种不同的标准Young表:
如果第一行表示“(”的位置、第二行表示“)”的位置,那么每个“标准Young表”都对应一个“匹配的括号串”。
其解等于第n个Catalan数。
3. 找零问题
2n个人要买票价为五元的电影票,每人只买一张,但是售票员没有钱找零。其中,n个人持有五元,另外n个人持有十元,问在不发生找零困难的情况下,有多少种排队方法?
其本质是“01序列”的变式:
我们把持有五元的人设为状态‘1’,持有十元的人设为状态‘0’。2n个人的所有状态对应n个 ‘1’ 和n个 ‘0’ 组成的2n位二进制数。
由于必须先有1个持有五元的人排在1个持有十元的人的前面,才能不发生找零困难,因此不发生找零困难排队方法的总数目=由左而右扫描由n个 ‘1’ 和n个 ‘0’ 组成的2n位二进制数,1的累计数不小于0的累计数的方案种数。
其解等于第n个Catalan数。
4. 二叉树计数
有n个节点构成的二叉树(非叶子节点都有2个儿子),共有多少种情形?
有n+1个叶子的二叉树的个数?
举例:n=3的情况:
其解等于第n个Catalan数。
5. 凸多边形划分
在一个n边形中,通过不相交于n边形内部的对角线,把n边形拆分为若干个三角形,问有多少种拆分方案?
如五边形有如下5种拆分方案:
如六边形有如下14种拆分方案:
其中f(2)相当于矩形被分成两部分,我们仍然看成三部分,其中一部分是一条线,无法组成三角形,为便于计算设f(2)=1
其解等于第n-2个Catalan数。
6. 圆上n条线段
在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
其解等于第n个Catalan数。
7. 不相交的弦
在一个圆周上分布着 个点,两两配对,并在这两个点之间连一条弦,要求所得的 条弦彼此不相交。
当 时,有如下5种不同的连弦方式:
从某一个特定的点开始,逆时针“前进”,如果“遇到”了“新的”弦,则写下一个“(”,如果“遇到”了“旧的”弦,则写下一个“)”。不相交的弦就转化为匹配的括号串。
转化为括号问题,其解等于第n个Catalan数。
8. 笔画“群峰”
使用 个斜向上的线段和 个相同长度的斜向下的线段,画出群峰。
当 n=3时,可以画出以下5种不同的群峰:
当 n=4时,可以画出以下14种不同的群峰:
如果用“(”取代斜向上的线段,用“)”取代斜向下的线段,则转化为“括号匹配”问题。
考虑第一次“回到水平面”的位置,可以如下分为和自身相同但是规模变小的两个子问题:
9. 格路问题
原点格路问题
从 (0,0) 点出发,每步只能沿 x 轴或 y 轴的正方向每步走一个单位,最终走到 (m,n) 点,有多少条路径?
格路问题的一般化
不能“接触”对角线的格路问题
当m=n+1时,利用组合数性质转化为卡特兰数
不能过对角线的格路问题
当m=n时,转化为卡特兰数
10. 填充阶梯图形
用n个长方形填充一个高度为n的阶梯状图形的方法个数?
举例:n=4的情况
其解等于第n个Catalan数。
一些简单的变式不再列举,当你能列出性质式C(2n,n)-C(n2,n-1)或者递推式的时候,就是卡塔兰数