卡特兰数
轻谈卡特兰数
卡特兰数是组合数学中常用到的一个数列;下面是百度百科的定义;
公式
1.另类递推式:
h(n)=h(n-1)*(4*n-2)/(n+1)
2.递推关系的解为:
h(n)=C(2n,n)/(n+1) (n=0,1,2,...)
3.递推关系的另类解为:
h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...)
4. h(n)=h(0)×h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0)
其前几项为 : 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, ...
附张图
应用
1、
出栈次序:一个栈(无穷大)的进栈次序为1、2、3……n。不同的出栈次序有几种。
我们可以这样想,假设k是最后一个出栈的数。比k早进栈且早出栈的有k-1个数,一共有h(k-1)种方案。比k晚进栈且早出栈的有n-k个数,一共有h(n-k)种方案。所以一共有h(k-1)*h(n-k)种方案。显而易见,k取不同值时,产生的出栈序列是相互独立的,所以结果可以累加。k的取值范围为1至n,所以结果就为h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0)。
出栈入栈问题有许多的变种,比如n个人拿5元、n个人拿10元买物品,物品5元,老板没零钱。问有几种排队方式。熟悉栈的同学很容易就能把这个问题转换为栈。值得注意的是,由于每个拿5元的人排队的次序不是固定的,所以最后求得的答案要*n!。拿10元的人同理,所以还要*n!。所以这种变种的最后答案为h(n)*n!*n!。
2、
二叉树构成问题。有n个结点,问总共能构成几种不同的二叉树。
我们可以假设,如果采用中序遍历的话,根结点第k个被访问到,则根结点的左子树有k-1个点、根结点的右指数有n-k个点。k的取值范围为1到n。讲到这里就很明显看得出是卡特兰数了。这道题出现在2015年腾讯实习生的在线笔试题中。有参加过的同学想必都有印象。
3、
凸多边形的三角形划分。一个凸的n边形,用直线连接他的两个顶点使之分成多个三角形,每条直线不能相交,问一共有多少种划分方案。
这也是非常经典的一道题。我们可以这样来看,选择一个基边,显然这是多边形划分完之后某个三角形的一条边。图中我们假设基边是p1pn,我们就可以用p1、pn和另外一个点假设为pi做一个三角形,并将多边形分成三部分,除了中间的三角形之外,一边是i边形,另一边是n-i+1边形。i的取值范围是2到n-1。所以本题的解c(n)=c(2)*c(n-1)+c(3)*c(n-2)+...c(n-1)*c(2)。令t(i)=c(i+2)。则t(i)=t(0)*t(i-1)+t(1)*t(i-2)...+t(i-1)*t(0)。很明显,这就是一个卡特兰数了。
这个并不是我写的,参考http://www.cnblogs.com/code-painter/p/4417354.html
例题
https://www.luogu.org/problem/show?pid=1044
题目背景
栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表。
栈有两种最重要的操作,即pop(从栈顶弹出一个元素)和push(将一个元素进栈)。
栈的重要性不言自明,任何一门数据结构的课程都会介绍栈。宁宁同学在复习栈的基本概念时,想到了一个书上没有讲过的问题,而他自己无法给出答案,所以需要你的帮忙。
题目描述
宁宁考虑的是这样一个问题:一个操作数序列,从1,2,一直到n(图示为1到3的情况),栈A的深度大于n。
现在可以进行两种操作,
1.将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的push操作)
- 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的pop操作)
使用这两种操作,由一个操作数序列就可以得到一系列的输出序列,下图所示为由1 2 3生成序列2 3 1的过程。
(原始状态如上图所示)
你的程序将对给定的n,计算并输出由操作数序列1,2,…,n经过操作可能得到的输出序列的总数。
输入输出格式
输入格式:
输入文件只含一个整数n(1≤n≤18)
输出格式:
输出文件只有一行,即可能输出序列的总数目
输入输出样例
输入样例#1:
3
输出样例#1:
5
我写的题解
这题的深搜算法!!!
经典的求出栈情况的卡特兰数
栈要有进才能有出,设进为0,出为1;
那么每个1前必有一个0;
所以,
n=1时 方法数s=1 (01)
n=2时 方法数s=2 (0011,0101)
n=3时 方法数s=5 (000111,001011,001101,010011,010101)
………………
也就是h(n)=h(0)*h(n-1)+h(1)*h(n-2)+……+h(n-1)*h(0)
但按这递推模拟的话,最后一个点会吃TLE;
所以蒟蒻我将前后对称的就乘2处理(值一样)
特判奇偶,分情况处理(奇数中间不用*2)
#include<bits/stdc++.h>
using namespace std;
int work(int n)
{
int s=0;
if ((n==1)||(n==0)) return 1;
int k=n%2;
for(int i=0;i<n/2;i++)
s+=2*work(i)*work(n-1-i);
for(int i=1;i<=k;i++)
s+=work(n/2)*work(n/2);
return s;
}
int main()
{
int n;
cin>>n;
cout<<work(n);
return 0;
}