卡特兰数专栏(HDU1023,HDU4165)

10 篇文章 0 订阅
1 篇文章 0 订阅

https://www.cnblogs.com/kuangbin/archive/2012/03/21/2410516.html

卡特兰数总结

卡特兰数又称卡塔兰数,是组合数学中一个常出现在各种计数问题中出现的数列。由以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)命名。

卡特兰数

前几项为 (OEIS中的数列A000108): 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(1)=1,h(2)=1,catalan数满足递归式:

例如:h(3)=h(1)h(2)+h(2)h(1)=11+11=2

h(4)=h(1)h(3)+h(2)h(2)+h(3)h(1)=12+11+21=5

若h(0)=1;h(1)=1;h(2)=2;h(3)=5; ····有另类的递归式

另类递归式:

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

该递推关系的解为:

h(n)=C(2n,n)/(n+1) (n=1,2,3,…)

卡特兰数的应用
  实质上都是递归等式的应用

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

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

分析

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

在2n位二进制数中填入n个1的方案数为c(2n,n),不填1的其余n位自动填0。从中减去不符合要求(由左而右扫描,0的累计数大于1的累计数)的方案数即为所求。

不符合要求的数的特征是由左而右扫描时,必然在某一奇数位2m+1位上首先出现m+1个0的累计数和m个1的累计数,此后的2(n-m)-1位上有n-m个 1和n-m-1个0。如若把后面这2(n-m)-1位上的0和1互换,使之成为n-m个0和n-m-1个1,结果得1个由n+1个0和n-1个1组成的2n位数,即一个不合要求的数对应于一个由n+1个0和n-1个1组成的排列。

反过来,任何一个由n+1个0和n-1个1组成的2n位二进制数,由于0的个数多2个,2n为偶数,故必在某一个奇数位上出现0的累计数超过1的累计数。同样在后面部分0和1互换,使之成为由n个0和n个1组成的2n位数,即n+1个0和n-1个1组成的2n位数必对应一个不符合要求的数。

因而不合要求的2n位数与n+1个0,n-1个1组成的排列一一对应。

显然,不符合要求的方案数为c(2n,n+1)。由此得出 输出序列的总数目=c(2n,n)-c(2n,n+1)=1/(n+1)*c(2n,n)。

(这个公式的下标是从h(0)=1开始的)

类似问题

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

类似:
  (1)有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)
  (2)在圆上选择2n个点,将这些点成对连接起来,使得所得到的n条线段不相交的方法数。

凸多边形三角剖分
  求将一个凸多边形区域分成三角形区域的方法数。

类似:一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果她从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?

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

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

给定节点组成二叉树
  给定N个节点,能构成多少种不同的二叉树?

(能构成h(N)个)

(这个公式的下标是从h(0)=1开始的)

例题:

HDU 1023 Train Problem II

Problem Description

As we all know the Train Problem I, the boss of the Ignatius Train Station want to know if all the trains come in strict-increasing order, how many orders that all the trains can get out of the railway.

Input

The input contains several test cases. Each test cases consists of a number N(1<=N<=100). The input is terminated by the end of file.

Output

For each test case, you should output how many ways that all the trains can get out of the railway.

Sample Input

1

2

3

10

Sample Output

1

2

5

16796

Hint

The result will be very large, so you may not process it by 32-bit integers.

Author

Ignatius.L

典型的出栈顺序问题。
程序:

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

#include<stdio.h>

///****************************************************
///打表卡特兰数
///第n个卡特兰数存在a[n]中,a[n][0]表示长度;
///注意数是倒着存的,个位是a[n][1],输出时注意倒过来
///*****************************************************

int a[105][100];
void Catalan()
{
    int i,j,yu,len;
    a[2][0] = 1;
    a[2][1] = 2;
    a[1][0] = 1;
    a[1][1] = 1;
    len = 1;
    for(i=3;i<101;i++)
    {
        yu = 0;
        for(j=1;j<=len;j++)
        {
            int t = (a[i-1][j]) *(4*i-2)+yu;
            yu = t/10;
            a[i][j] = t%10;
        }
        while(yu)
        {
            a[i][++len] = yu %10;
            yu/=10;
        }
        for(j=len;j>=1;j--)
        {
            int t=a[i][j] + yu*10;
            a[i][j] = t/(i+1);
            yu = t%(i+1);
        }
        while(!a[i][len])
        {
            len--;
        }
        a[i][0] = len;
    }
}

int main()
{
    Catalan();
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=a[n][0];i>0;i--)
        {
            printf("%d",a[n][i]);
        }
        printf("\n");
    }
    return 0;
}

HDU 4165 Pills 属于一样的题目;

复制代码
//h( n ) = ( ( 4*n-2 )/( n+1 )*h( n-1 ) );

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

#include<stdio.h>

///****************************************************
///打表卡特兰数
///第n个卡特兰数存在a[n]中,a[n][0]表示长度;
///注意数是倒着存的,个位是a[n][1],输出时注意倒过来
///*****************************************************

int a[105][100];
void Catalan()
{
    int i,j,yu,len;
    a[2][0] = 1;
    a[2][1] = 2;
    a[1][0] = 1;
    a[1][1] = 1;
    len = 1;
    for(i=3;i<101;i++)
    {
        yu = 0;
        for(j=1;j<=len;j++)
        {
            int t = (a[i-1][j]) *(4*i-2)+yu;
            yu = t/10;
            a[i][j] = t%10;
        }
        while(yu)
        {
            a[i][++len] = yu %10;
            yu/=10;
        }
        for(j=len;j>=1;j--)
        {
            int t=a[i][j] + yu*10;
            a[i][j] = t/(i+1);
            yu = t%(i+1);
        }
        while(!a[i][len])
        {
            len--;
        }
        a[i][0] = len;
    }
}

int main()
{
    Catalan();
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=a[n][0];i>0;i--)
        {
            printf("%d",a[n][i]);
        }
        printf("\n");
    }
    return 0;
}

学习一下大佬的博客总结https://blog.csdn.net/wu_tongtong/article/details/78161211
计算公式
卡特兰数一般的计算公式:
另类递推公式:C(n)=C(n-1)((4n-2)/(n+1));

一般性质
Cn的另一个表达形式为
所以,Cn是一个自然数,这一点在先前的通项公式中并不显而易见。
这个表达形式也是André对前一公式证明的基础。

卡塔兰数满足以下递推关系

它也满足

这提供了一个更快速的方法来计算卡塔兰数。

卡塔兰数的渐近增长为

它的含义是左式除以右式的商趋向于1当n → ∞。(这可以用n!的斯特灵公式来证明。)

所有的奇卡塔兰数Cn都满足n = 2^k − 1。
所有其他的卡塔兰数都是偶数。

实际问题的解决
说了这么多,那么卡特兰数在实际问题中的应用还是很广泛的:

经典问题:

给出一个n,要求一个长度为2n的01序列,使得序列的任意前缀中1的个数不少于0的个数,
以下为长度为6的序列:
111000 101100 101010 110010 110100
证明:
令1表示进栈,0表示出栈,则可转化为求一个2n位,含n个1,n个0的二进制数,
满足从左往右扫描到任意一位时,经过的0数不多于1数
显然含n个1,n个0的2n位二进制数共有个,下面考虑不满足要求的数目.
考虑一个含n个1,n个0的2n位二进制数,扫描到第2m+1位上时有m+1个0和m个1(容易证明一定存在这样的情况),
则后面的01排列中必有n-m个1和n-m-1个0
将2m+2及其以后的部分0变成1,1变成0,则对应一个n+1个0和n-1个1的二进制数
反之亦然(相似的思路证明两者一一对应)
从而

将上例的X换成左括号,Y换成右括号,Cn表示所有包含n组括号的合法运算式的个数:
((())) ()(()) ()()() (())() (()())

Cn表示有n+1个叶子的二叉树的个数

Cn表示所有不同构的含n个分枝结点的满二叉树的个数(一个有根二叉树是满的当且仅当每个结点都有两个子树或没有子树)

Cn表示所有在n × n格点中不越过对角线的单调路径的个数
一个单调路径从格点左下角出发,在格点右上角结束,每一步均为向上或向右
计算这种路径的个数等价于计算Dyck word的个数(同问题1):
X代表“向右”,Y代表“向上”

Cn表示通过连结顶点而将n + 2边的凸多边形分成三角形的方法个数
下图中为n = 4的情况:

Cn表示对{1, …, n}依序进出栈的置换个数
一个置换w是依序进出栈的当S(w) = (1, …, n),
其中S(w)递归定义如下:令w = unv,其中n为w的最大元素,u和v为更短的数列
再令S(w) =S(u)S(v)n,其中S为所有含一个元素的数列的单位元。

Cn表示集合{1, …, n}的不交叉划分的个数. 其中每个段落的长度为2

Cn表示用n个长方形填充一个高度为n的阶梯状图形的方法个数
下图为 n = 4的情况:

总结最典型的四类应用:
(实质上却都一样,无非是递归等式的应用,就看你能不能分解问题写出递归式了)

括号化问题。

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

出栈次序问题。
  一个栈(无穷大)的进栈序列为1,2,3,…n,有多少个不同的出栈序列?
  
  类似:
  (1)有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)
  
  (2)在圆上选择2n个点,将这些点成对连接起来,使得所得到的n条线段不相交的方法数。

将多边行划分为三角形问题。
  将一个凸多边形区域分成三角形区域的方法数?
  
  类似:一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果她从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?
  
  类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
  
4.给顶节点组成二叉树的问题。
  给定N个节点,能构成多少种形状不同的二叉树?
  先去一个点作为顶点,然后左边依次可以取0至N-1个相对应的,右边是N-1到0个,两两配对相乘,就是h(0)*h(n-1) + h(2)*h(n-2) +…+ h(n-1)h(0)=h(n)(能构成h(N)个)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值