Catalan

卡特兰数前几项为 : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900,2674440, 9694845,35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ... 令h(0)=1,h(1)=1,

catalan数满足递推式[1]:

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2) 例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2 h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5

递推关系的另类解为: h(n)=c(2n,n)-c(2n,n+1)(n=0,1,2,...)

卡特兰数的递推公式为:h(n)=h(n-1)*(4*n-2)/(n+1);

应用问题 实质上都是递推等式的应用 : 1:矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序, 只用括号表示成对的乘积, 试问有几种括号化的方案?(h(n-1)种)[3]出栈次序

2: 一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列?[4-5]

3: 类似问题 买票找零 有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票, 剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零? (将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)

4:

凸多边形三角划分 在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。 现在的任务是键盘上输入凸多边形的边数n,求不同划分的方案数f(n)。比如当n=6时,f(6)=14。[6] 分析

因为凸多边形的任意一条边必定属于某一个三角形,所以我们以某一条边为基准, 以这条边的两个顶点为起点P1和终点Pn(P即Point),将该凸多边形的顶点依序标记为P1、P2、……、Pn, 再在该凸多边形中找任意一个不属于这两个点的顶点Pk(2<=k<=n-1),来构成一个三角形, 用这个三角形把一个凸多边形划分成两个凸多边形,其中一个凸多边形,是由P1,P2,……, Pk构成的凸k边形(顶点数即是边数),另一个凸多边形,是由Pk,Pk+1,……,Pn构成的凸n-k+1边形。 此时,我们若把Pk视为确定一点,那么根据乘法原理,f(n)的问题就等价于——凸k多边形的划分方案数乘 以凸n-k+1多边形的划分方案数,即选择Pk这个顶点的f(n)=f(k)×f(n-k+1)。 而k可以选2到n-1,所以再根据加法原理,将k取不同值的划分方案相加,得到的总方案数为: f(n)=f(2)f(n-2+1)+f(3)f(n-3+1)+……+f(n-1)f(2)。看到此处,再看看卡特兰数的递推式, 答案不言而喻,即为f(n)=h(n-2) (n=2,3,4,……)。 最后,令f(2)=1,f(3)=1。 此处f(2)=1和f(3)=1的具体缘由须参考详尽的“卡特兰数”, 也许可从凸四边形f(4)=f(2)f(3)+ f(3)f(2)=2×f(2)f(3)倒推, 四边形的划分方案不用规律推导都可以知道是2,那么2×f(2)f(3)=2,则f(2)f(3)=1, 又f(2)和f(3)若存在的话一定是整数,则f(2)=1,f(3)=1。

5:

类似问题 编辑本段 一位大城市的律师在她住所以北n个街区和以东n个街区处工作。 每天她走2n个街区去上班。如果她从不穿越(但可以碰到)从家到办公室的对角线, 那么有多少条可能的道路? 在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?

下面总结了卡特兰数的一个模板 这里用的是 卡特兰数的递推公式为:h(n)=h(n-1)*(4*n-2)/(n+1); 也就是一个高精度问题的求解

hdu:1134

#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace std;

int a[105][105];    //大数卡特兰数
int b[105];         //卡特兰数的长度
void catalan()  //求卡特兰数

{
    int i, j, len, carry, temp;
    a[1][0] = b[1] = 1;
    len = 1;
    for(i = 2; i <= 100; i++)

 {
        for(j = 0; j < len; j++)    //乘法
            a[i][j] = a[i-1][j]*(4*(i-1)+2);
        carry = 0;
        for(j = 0; j < len; j++)    //处理相乘结果

     {
            temp = a[i][j] + carry;
            a[i][j] = temp % 10;
            carry = temp / 10;
       }

   while(carry)    //进位处理
        {
            a[i][len++] = carry % 10;//这里这样写是为了记住b[i]所对应的len
            carry /= 10;
        }
        carry = 0;
        for(j = len-1; j >= 0; j--) //除法,这里看的不是很懂。比如28/6的话就等于4了
        {
            temp = carry*10 + a[i][j];
            a[i][j] = temp/(i+1);
            carry = temp%(i+1);
        }

        while(!a[i][len-1])     //高位零处理
            len --;
        b[i] = len;
    }
}

int main()
{
    int i, n;
    catalan();
    while(scanf("%d", &n) != EOF)
    {

         for(i = b[n]-1; i>=0; i--)//这样话,对于打表求解的话确实很省时间
        {
            printf("%d", a[n][i]);
        }

        printf(" ");   

     }

    return 0;

}

 问题描述:
12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
这个笔试题,很YD,因为把某个递推关系隐藏得很深。

问题分析:
我们先把这12个人从低到高排列,然后,选择6个人排在第一排,那么剩下的6个肯定是在第二排.
用0表示对应的人在第一排,用1表示对应的人在第二排,那么含有6个0,6个1的序列,就对应一种方案.
比如000000111111就对应着
第一排:0 1 2 3 4 5
第二排:6 7 8 9 10 11
010101010101就对应着
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
问题转换为,这样的满足条件的01序列有多少个。
观察1的出现,我们考虑这一个出现能不能放在第二排,显然,在这个1之前出现的那些0,1对应的人
要么是在这个1左边,要么是在这个1前面。而肯定要有一个0的,在这个1前面,统计在这个1之前的0和1的个数。
也就是要求,0的个数大于1的个数。
OK,问题已经解决。

原文地址:https://www.cnblogs.com/ACWQYYY/p/4312282.html