组合数学 —— 卡特兰数列(Catalan)

【概述】

卡特兰数列是组合数学中一个常出现在各种计数问题中出现的数列,其前几项为 : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, ......

卡特兰数首先是由欧拉在计算对凸 n 边形的不同的对角三角形剖分的个数问题时得到的,即在一个凸 n 边形中,通过不相交于 n 边形内部的对角线,把 n 边形拆分成若干三角形,不同的拆分数目用 Hn 表示,Hn 即为卡特兰数。

【公式】

1.递归公式 1

f(n)=\sum_{i=0}^{n-1}f(i)*f(n-i-1)

2.递归公式 2

f(n)=\frac{f(n-1)*(4*n-2)}{(n+1)}

3.组合公式 1

f(n)=\frac{C_{2n}^n}{(n+1)}

4.组合公式 2

f(n)=C_{2n}^n-C^{n-1}_{2n}

【应用】

  1. 二叉树的计数:已知二叉树有 n 个结点,求能构成多少种不同的二叉树
  2. 括号化问题:一个合法的表达式由()包围,()可以嵌套和连接,如:(())()也是合法表达式,现给出 n 对括号,求可以组成的合法表达式的个数
  3. 划分问题:将一个凸 n+2 多边形区域分成三角形区域的方法数
  4. 出栈问题:一个栈的进栈序列为1,2,3,..n,求不同的出栈序列有多少种
  5. 路径问题:在 n*n 的方格地图中,从一个角到另外一个角,求不跨越对角线的路径数有多少种
  6. 握手问题:2n 个人均匀坐在一个圆桌边上,某个时刻所有人同时与另一个人握手,要求手之间不能交叉,求共有多少种握手方法

【实现】

1.n<=35 的卡特兰数的实现

LL h[36];
void init() {
    h[0]=h[1]=1;
    for(int i=2; i<=35; i++) {
        h[i]=0;
        for(int j=0; j<i; j++)
            h[i]=h[i]+h[j]*h[i-j-1];
        cout<<h[i]<<endl;
    }
}

2.n<100 的卡特兰数的实现

#define BASE 10000
int a[100+5][100];
void multiply(int num,int n,int b) {//大数乘法
    int temp=0;
    for(int i=n-1; i>=0; i--) {
        temp+=b*a[num][i];
        a[num][i]=temp%BASE;
        temp/=BASE;
    }
}
void divide(int num,int n,int b) {//大数除法
    int div=0;
    for(int i=0; i<n; i++) {
        div=div*BASE+a[num][i];
        a[num][i]=div/b;
        div%=b;
    }
}
void init(){
    memset(a,0,sizeof(a));
    a[1][100-1]=1;
    for(int i=2; i<=100; i++) {
        memcpy(a[i],a[i-1],sizeof(a[i-1]));
        multiply(i,100,4*i-2);
        divide(i,100,i+1);
    }
}
int main() {
    init();
    int n;
    while(scanf("%d",&n)!=EOF){
        int i;
		for(i=0;i<100 && a[n][i]==0;i++);
            printf("%d",a[n][i++]);
		for(;i<100;i++)
			printf("%04d",a[n][i]);
		 printf("\n");
	}
    return 0;
}

 【例题】

  • 小兔的棋盘(HDU-2067)(n<=35的卡特兰数)点击这里
  • Game of Connections(POJ-2084)(n<100的卡特兰数)点击这里
  • 小a的学期(2019牛客寒假算法基础集训营 Day1-H)(卡特兰数列+组合数取模)点击这里
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值