卡特兰数

来源:互联网 发布:abp源码 编辑:程序博客网 时间:2024/05/17 01:31

                                                                卡特兰数

轻谈卡特兰数
      卡特兰数是组合数学中常用到的一个数列;下面是百度百科的定义;

公式
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操作)

  1. 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的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;}

原创粉丝点击