数据结构作业中出现了这样一道题:给出序列1,2,3,4...n。将这个n个数入栈。求最后的输出序列的方案数。
我们先模拟可以得到:f(1) = 1, f(2) = 2, f(3) = 5, f(4) =14;
因为抱着这样的题是有规律的,我到网上搜了一下,还真有,这样的数叫卡特兰数。
公式如下: ,或者
或者为递推关系:和
而对于这道题的证明是利用的递推关系1.
证明:我们考虑n个数中1这个数在最终的输出序列的出现的位置。如果它出现在第i个位置,那它前面就i-1个数字,后面就有n-i个数字。
而对于前i-1个数字,一定是从2到i,同时仍然是递增的顺序排列,这样我们就转化成立求i-1个输入数字的输出序列的方案数,设其大小为C(i-1).
同样,对于后面的n-i个数字,方案数同样为C(n-i)。
所以,对于第i个位置,总的方案数为C(i-1)C(n-i).
而对于所有的位置,C(n) = ∑C(i-1)C(n-i). 这就是上面的卡特兰数的递推关系1.
但是,卡特兰数的魅力还不在这里。对于很多卡特兰数适用的问题,都可以转化成括号序列,即n个左括号,n个右括号,有多少种合法的匹配方法。
而对于上面的一道题,我们可以将进栈看做左括号,出栈看做右括号。只不过这里的括号可以认为成数,而最后的输出序列,就是从前往后把所有的右括号的数提取出来罢了。
下面是关于卡特兰数的几个应用:
n个+1和n个-1构成2n项,其部分和满足
的序列个数等于第n个Catalan数
。
其证明也不难,我们假设不满足条件的序列个数为,那么就有
。剩下的工作就是求
了,我们假设有一个最小的k令
。由于这里k是最小的,所以必有
,并且k是一个奇数。此时我们将前k项中的+1变为-1,将-1变为+1,那么就得到一个有(n+1)个+1和(n-1)个-1的序列了,这样的序列个数就是我们要求的
,数值大小为
。那么我们就得到了
,就是我们前面的公式。
在具体的组合数问题中,很多都可以转换为Catalan数进行最后的计算,如下:
1、如上文所说,对于任意的k,前k个元素中-1的个数小等于+1的个数的序列计数,我们可以不停地变换形式,比如将-1看成右括号,+1看成左括号,就变成了合法括号表达式的个数。比如2个左括号和2个右括号组成的合法表达式有种,是()()和(())。
2、既然如上一点都把括号加上去了,那么顺便就再次转换,n+1个数连乘,乘法顺序有种,比如我们三个数连乘a*b*c,那么等于在式子上加括号,有2种乘法顺序,分别是(ab)c和a(bc)。貌似对应关系比较模糊,我们取n为3来看看,n为3的时候就是4个数相乘了,那么我们设为abcd,最初的标号定在a上,我们对于n为3得到合法的括号序列有5个,分别是:((())),()(()),()()(),(())()和(()()),那么我们将一个左括号看成是当前操作数指针往右移动一个位置,一个右括号看成是当前操作数和左边最近的一块操作数相乘起来,那么对应的五个表达式就是:a(b(cd)),(ab)(cd),((ab)c)d,(a(bc))d和a((bc)d),他们之间是一一对应关系。
3、n个节点的二叉树的所有可能形态数为,这一点很容易证明,我们考虑随便取一个节点作为根,那么他左边和右边的儿子节点个数就确定了,假定根节点标号为x,那么左子树的标号就从1到x-1,共x-1个,右子树的标号就从x+1到n,共n-x个,那么我们的x从1取到n,就获得了所有的情况数
。这个式子就是我们性质3的式子。
4、n个非叶节点的满二叉树的形态数(对称后得到的二叉树除非自己本身对称,否则算是不同),这里取Wikipedia上的一张图片说明问题:
这里要求满二叉树,实际上就是在上一点的每个子节点的空儿子上都加上叶子,就形成了我们的图了,那么我们要求的结果就是Catalan数。
5、对于一个n*n的正方形网格,每次我们能向右或者向上移动一格,那么从左下角到右上角的所有在副对角线右下方的路径总数为。同样引用Wikipedia上的一张图片来表示:
我们将一条水平边记为+1,垂直边记为-1,那么就组成了一个n个+1和n个-1的序列,我们所要保证的就是前k步中水平边的个数不小于垂直边的个数,换句话说前k个元素的和非负,就是我们关于Catalan数的定义。
6、凸n+2边形进行三角形分割(只连接顶点对形成n个三角形)数:
7、n个数入栈后的出栈的排列总数是。例如1,2,3入栈的出栈排序有123,132,213,231和321五种
8、对于集合的不交叉划分的数目为
,这里解释一下不交叉划分,我们对于集合{a,b}和{c,d},假设他们组成了两个区间[a,b]和[c,d],我们假设两个区间不重合,那么以下四种情况当做是不交叉的:a<c<d<b,a<b<c<d,c<a<b<d与c<d<a<b,就是说两个区间可以包含或者相离,那么此时我们称集合{a,b}和{c,d}是不交叉的。对于集合
,将里面元素两两分为一子集,共n个,若任意两个子集都是不交叉的,那么我们称此时的这个划分为一个不交叉划分。此时不交叉的划分数就是我们的
了,证明也很容易,我们将每个子集中较小的数用左括号代替,较大的用右括号代替,那么带入原来的1至2n的序列中就形成了合法括号问题,就是我们第二点的结论。例如我们的集合{1,2,3,4,5,6}的不交叉划分有五个:{{1,2},{3,4},{5,6}},{{1,2},{3,6},{4,5}},{{1,4},{2,3},{5,6}},{{1,6},{2,3},{4,5}}和{{1,6},{2,5},{3,4}}。
9、n层的阶梯切割为n个矩形的切法数也是。如下图所示:
这个证明是怎么进行的呢?我们先绘制如下的一张图片,即n为5的时候的阶梯:
我们注意到每个切割出来的矩形都必需包括一块标示为*的小正方形,那么我们此时枚举每个*与#标示的两角作为矩形,剩下的两个小阶梯就是我们的两个更小的子问题了,于是我们的注意到这里的式子就是我们前面的性质3,因此这就是我们所求的结果了。
10、在一个2*n的格子中填入1到2n这些数值使得每个格子内的数值都比其右边和上边的所有数值都小的情况数也是。
11、平面上连接可以形成凸包的2n个点分成2个一组连成n条线段,两两线段之间不相交的情况总数是,这里实际上和第7点本质上是一样的,这里就不解释了。
Catalan数问题的一个变形:
n+m个人排队买票,并且满足,票价为50元,其中n个人各手持一张50元钞票,m个人各手持一张100元钞票,除此之外大家身上没有任何其他的钱币,并且初始时候售票窗口没有钱,问有多少种排队的情况数能够让大家都买到票。
这个题目是Catalan数的变形,不考虑人与人的差异,如果m=n的话那么就是我们初始的Catalan数问题,也就是将手持50元的人看成是+1,手持100元的人看成是-1,任前k个数值的和都非负的序列数。
这个题目区别就在于n>m的情况,此时我们仍然可以用原先的证明方法考虑,假设我们要的情况数是,无法让每个人都买到的情况数是
,那么就有
,此时我们求
,我们假设最早买不到票的人编号是k,他手持的是100元并且售票处没有钱,那么将前k个人的钱从50元变成100元,从100元变成50元,这时候就有n+1个人手持50元,m-1个手持100元的,所以就得到
,于是我们的结果就因此得到了,表达式是
。
关于公式2的直观法证明:
事实上,可以认为问题是,任意两种操作,要求每种操作的总次数一样,且进行第k次操作2前必须先进行至少k次操作1。我们假设一个人在原点,操作1是此人沿右上角45°走一个单位(一个单位设为根号2,这样他第一次进行操作1就刚好走到(1,1)点),操作2是此人沿右下角45°走一个单位。第k次操作2前必须先进行至少k次操作1,就是说明所走出来的折线不能跨越x轴走到y=-1这条线上!在进行n次操作1和n此操作2后,此人必将到到达(2n,0)!若无跨越x轴的限制,折线的种数将为C(2n,n),即在2n次操作中选出n次作为操作1的方法数。
![折线法](https://i-blog.csdnimg.cn/blog_migrate/6aefa914e4977ad0d9a63e48b312328d.jpeg)
现在只要减去跨越了x轴的情况数。对于任意跨越x轴的情况,必有将与y=-1相交。找出第一个与y=-1相交的点k,将k点以右的折线根据y=-1对称(即操作1与操作2互换了)。可以发现终点最终都会从(2n,0)对称到(2n,-2)。由于对称总是能进行的,且是可逆的。我们可以得出所有跨越了x轴的折线总数是与从(0,0)到(2n,-2)的折线总数。而后者的操作2比操作1要多0-(-2)=2次。即操作1为n-1,操作2为n+1。总数为C(2n,n-1)。
![折线法](https://i-blog.csdnimg.cn/blog_migrate/a9edc93c9fd45ecfc6d8166496dcda52.jpeg)