Catalan 卡特兰数

卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名,其前几项为 : 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, …


Catalan的递推关系

h(0)=1,h(1)=1 ,catalan数满足递推式
h(n)=h(0)h(n1)+h(1)h(n2)+...+h(n1)h(0)(n>=2)

cat[0]=cat[1]=1;
for(int i=2;i<=n;++i)
for(int j=0;j<i;++j)
cat[i]+=cat[j]*cat[i-j-1];

递推复杂度为O(n^2)


h(0)=1,h(1)=1
则有 h(n)=h(n1)(4n2)/(n+1)

cat[0]=cat[1]=1;
for(int i=2;i<=n;++i)
cat[i]=cat[i-1]*(4*i-2)/(i+1);

递推复杂度为O(n)


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

h(n)=c(2n,n)c(2n,n1)
代码先坑着= =


Catalan的应用

入栈出栈

Q:给定n个数,进栈的序列是1,2,3,4,…..n,有多少个不同的出栈次序
A:
h(n)表示个数为n的序列的出栈次序种数
假设最后出栈的元素是k
k入栈前k前面的元素都出栈,所以有 h(k1)
k后面的元素在k之前出栈,所以有 h(nk)

运用乘法原理有 h(n)=h(k1)h(nk)
由于k可以取1到n,根据加法原理得
h(n)=h(0)h(n1)+h(1)h(n2)+...+h(n1)h(0)(n>=2)
也就是卡特兰数得递推式


平衡括号

Q:有n个左括号,n个右括号,总共2*n个括号,有多少种合法匹配方式,
A:
左括号视为入栈右括号视为出栈
那么这个问题就转化成了将n个左括号入栈,有多少种合法出栈次序得问题
也就是上面的出栈入栈问题,答案就是 h(n)


二叉树的形态

Q:有n个结点得二叉树,可以有多少种不同形态
A:
以h(n)表示有n个节点的二叉树可以有得不同形态数
假设其根得左子树有k个节点
那么其左子树 h(k) 个不同形态,右子树 h(nk1) 个不同形态
根据乘法原理 h(n)=h(k)h(nk1)
k可以取0-n
则有 h(n)=h(0)h(n1)+h(1)h(n2)+...+h(n1)h(0)(n>=2)
满足卡特兰数递推式


走方格

Q:一个 n*n 的方格,从左下角走到右上角,只能向右和向上走,但是不能绕过左下角和右上角确定的对角线,问有多少种走法?
A:
要走到右上角,需要向右走n布,向上走n步
向右走看作进栈,向左走看作出栈,本质就是n个数出栈次序的问题


还有很多应用
待更。。。。


Catalan数例题

题目背景

盛况空前的足球赛即将举行。球赛门票售票处排起了球迷购票长龙。

按售票处规定,每位购票者限购一张门票,且每张票售价为50元。在排成长龙的球迷中有N个人手持面值50元的钱币,另有N个人手持面值100元的钱币。假设售票处在开始售票时没有零钱。试问这2N个球迷有多少种排队方式可使售票处不致出现找不出钱的尴尬局面。

题目描述

例如当n=2是,用A表示手持50元面值的球迷,用B表示手持100元钱的球迷。则最多可以得到以下两组不同的排队方式,使售票员不至于找不出钱。
第一种:A A B B
第二种:A B A B
对于给定的n (0≤n≤20),计算2N个球迷有多少种排队方式,可以使售票处不至于找不出钱。

输入格式:

一个整数,代表N的值

输出格式:

一个整数,表示方案数


分析

一个A买票后售票处就积累50元钱
一个B买票需要售票处找零50元钱
说明在一个B买票前至少需要一个A买过票
那么我们就可以将A看作左括号,B看作右括号
问题就是要求合法得括号匹配,即Catalan数

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;

int n;
ll cat[50];

int main()
{
    scanf("%d",&n);
    cat[0]=cat[1]=1;

    for(int i=2;i<=n;++i)
    cat[i]=cat[i-1]*(4*i-2)/(i+1);

    cout<<cat[n];
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/80017831