卡特兰数

来源:互联网 发布:javascript encodeuri 编辑:程序博客网 时间:2024/04/30 06:08

Codeblock的快捷键说明:

1、按住Ctrl滚滚轮,代码的字体会随你心意变大变小

2 在编辑区按住右键可拖动代码

3Ctrl+D可复制当前行或选中块

4Ctrl+Shift+C注释掉当前行或选中块,Ctrl+Shift+X则解除注释。

5Tab缩进当前行或选中块,Shift+Tab减少缩进

6、需要更大编辑空间时,F2Shift+F2分别可以显隐下方Logs & others栏和左方的Management

7Ctrl+PageUp 到达上一个函数,Ctrl+PageDown 到达下一个函数。 •Ctrl+B 添加书签

 

 

void *memset(void *s,int ch,size_t n);

函数解释:将 s 中前 n 个字节用 ch 替换并返回 s

头文件:#include


 

//卡特兰数:

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0)(n>=2)

 

h(n)=C(2n,n)/(n+1) (n=0,1,2,...)

 

h(n ) = h(n-1)*(4*n-2) / (n+1)

 

 

卡特兰数:规定h(0)1,而h(1)1h(2)2h(3)5h(4)14h(5)42h(6)132h(7)429h(8)1430h(9)4862h(10)16796h(11)58786h(12)208012h(13)742900h(14)2674440h(15)9694845···

 

1,1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012,742900, 2674440, 9694845, 35357670, …

 

应用:

1、括号化

矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n-1))

f(n) = f(1)*f(n-1) + f(2)*f(n-2) + f(3)*f(n-3) +f(n-1)*f(1)

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0)(n>=2)

f(n) =h(n-1)   n>=3(因为hn)中,n>=2)

2、出栈次序

一个栈(无穷大)的进栈序列为123,…,n,有多少个不同的出栈序列?

分析:对于每一个数来说,必须进栈一次、出栈一次。我们把进栈设为状态‘1’,出栈设为状态‘0’。n个数的所有状态对应n1n0组成的2n位二进制数。由于等待入栈的操作数按照1n的顺序排列、入栈的操作数b大于等于出栈的操作数a(ab),因此输出序列的总数目=由左而右扫描由n1n0组成的2n位二进制数,1的累计数不小于0的累计数的方案种数。

   n个数的进栈次序和出栈次序构成了一个含2n个数字的序列。第0个数字肯定是进栈的数,这个数相应的出栈的数一定是第2i+1个数。因为如果是2i,那么中间包含了奇数个数,这奇数个肯定无法构成进栈出栈序列。

设问题的解为f(2n),那么

f(2n) = f(0)*f(2n-2) + f(2)*f(2n-4) +f(2n-2)*f(0)

f(2n) = h(n)

 

类似问题:

n对括号有多少种匹配方式?(hn) )

3、凸多边形三角划分

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

分析:因为凸多边形的任意一条边必定属于某一个三角形,所以我们以某一条边为基准,以这条边的两个顶点为起点P1和终点PnPPoint),将该凸多边形的顶点依序标记为P1P2、……、Pn,再在该凸多边形中找任意一个不属于这两个点的顶点Pk2<=k<=n-1),来构成一个三角形,用这个三角形把一个凸多边形划分成两个凸多边形,其中一个凸多边形,是由P1P2,……,Pk构成的凸k边形(顶点数即是边数),另一个凸多边形,是由PkPk+1,……,Pn构成的凸n-k+1边形。

此时,我们若把Pk视为确定一点,那么根据乘法原理,fn)的问题就等价于——凸k多边形的划分方案数乘以凸n-k+1多边形的划分方案数,即选择Pk这个顶点的fn=fk)×fn-k+1)。而k可以选2n-1,所以再根据加法原理,将k取不同值的划分方案相加,得到的总方案数为:

fn=f2fn-2+1+f3fn-3+1+……+fn-1f2)。

fn=hn-2)(n=234,……)。

最后,令f2=1f3=1

 

思路:以凸多边形的一边为基,设这条边的2个顶点为AB。从剩余顶点中选1个,可以将凸多边形分成三个部分,中间是一个三角形,左右两边分别是两个凸多边形,然后求解左右两个凸多边形。

设问题的解f(n),其中n表示顶点数,设f(2) = 1,那么f(3) = 1, f(4) = 2, f(5) = 5f(2)*f(n-1)表示三个相邻的顶点构成一个三角形,那么另外两个部分的顶点数分别为2n-1。那么

f(n) = f(2)*f(n-1) + f(3)*f(n-2) +......f(n-2)*f(3) + f(n-1)*f(2)

f(n) = h(n-2)

 

类似问题:

在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?

思路:以其中一个点为基点,编号为0,然后按顺时针方向将其他点依次编号。那么与编号为0相连点的编号一定是奇数,否则,这两个编号间含有奇数个点,势必会有个点被孤立,即在一条线段的两侧分别有一个孤立点,从而导致两线段相交。设选中的基点为A,与它连接的点为B,那么AB将所有点分成两个部分,一部分位于AB的左边,另一部分位于AB的右边。然后分别对这两部分求解即可。

设问题的解f(n),那么

f(n) = f(0)*f(n-2) + f(2)*f(n-4) + f(4)*f(n-6) +......f(n-4)*f(2) + f(n-2)*f(0)

f(0)*f(n-2)表示编号0的点与编号1的点相连,此时位于它们右边的点的个数为0,而位于它们左边的点为2n-2。依次类推。

f(0) = 1, f(2) = 1, f(4) = 2。结合递归式,不难发现

f(2n) =h(n)

 

Cn = n*n 的方格地图中,从一个角到另外一个角,不跨越对角线的路径数;

4、给定节点组成二叉树

给定N个节点,能构成多少种不同的二叉树?(能构成hN)个)(这个公式的下标是从h(0)=1开始的)

思路:可以这样考虑,根肯定会占用一个结点,那么剩余的n-1个结点可以有如下的分配方式,T(0, n-1),T(1, n-2),...T(n-1, 0),设T(i, j)表示根的左子树含i个结点,右子树含j个结点。

设问题的解为f(n),那么

假设f(0) = 1,那么f(1) = 1, f(2) = 2, f(3) =5

f(n) = f(0)*f(n-1) + f(1)*f(n-2) + .......+f(n-2)*f(1) + f(n-1)*f(0)

f(n) = h(n).

 

实例:

1描述:有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?

    思路:可以将持5元买票视为进栈,那么持10元买票视为5元的出栈。这个问题就转化成了栈的出栈次序数。由应用2的分析直接得到结果,

f(2n) = h(n)*n!*n!。(后面的*n!*n!为进出栈的排列)

 

2、拥有n+1个叶子节点的二叉树的数量为h(n)

 

 

编程实例:

// 使用公式计算:h(n ) = h(n-1)*(4*n-2) / (n+1)

 

#include

#include

using namespace std;

//h(n ) = h(n-1)*(4*n-2) / (n+1)

int catelan1(int n)

{

   if(n==0) return 1;

    elsereturn catelan1(n-1)*(4*n-2)/(n+1);

}

 

//h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0)(n>=2)

int catelan2(int n)

{

    inti,j,h[100];

   memset(h, 0, sizeof(h));

   h[0]=h[1]=1;

    for(i=2; i<=n; i++)

    for(j=0; j

        h[i] += h[j]*h[i-1-j];

    return h[n];

}

//h(n)=C(2n,n)/(n+1) (n=0,1,2,...)

int Cn(int n)

{

    inti,sum=1;

   for(i=1; i<=n; i++)

   sum*=i;

   return sum;

}

int catelan3(int n)

{

   return Cn(2*n)/Cn(n)/Cn(n)/(n+1);

}

int main()

{

   for(int i=0; i<=10; i++)

   cout<<"h("<<i<<"):"<<catelan1(i)<<endl;

}

 

运行结果:

h(0):1

h(1):1

h(2):2

h(3):5

h(4):14

h(5):42

h(6):132

h(7):429

h(8):1430

h(9):4862

h(10):16796

 

Process returned 0(0x0)   execution time : 0.234s

Press any key to continue.

公式3有点问题。。。

 

还有一种分级排列法,没怎么看明白。。。