zoukankan      html  css  js  c++  java
  • 卡特兰数

    卡特兰数有关的问题,大都满足这样一个描述:
    有一个大问题A,规模为n,要解决这个问题,可以用分治的思想,首先固定其中某一个元素,将剩下的n-1个元素拆分成两个小问题,这两个小问题的规模分别是(0,n-1) (1,n-2) (2,n-3) ... (n-1,0)

    举几个例子:
    1. 二叉树计数,n个结点的二叉树,首先固定根节点,将剩下的n-1个结点拆分给左右子树
    2. 三角形划分问题,凸(n+2)边形可以划分为n个三角形,首先固定一条边(即一个三角形),这个三角形将这个(n+2)边形拆分成两个更小的多边形。

    假设使用(表示进栈,)表示出栈。合法的进出栈序列,就等价于合法的括号序列。




    先扔出结论:如果有n对括号(称()为括号),合法表达式的个数是C_n=inom{2n}{n}-inom{2n}{n+1}=frac{1}{n+1}inom{2n}{n}.


    首先,为了更加直观地求这个值,可以把这个问题映射到下面的这个图论问题:
    (路径问题) 在一个n	imes n 的网格里,只能往上或往右走,从(0,0)出发到(n,n),且不穿过(可以到达) (0,0)和(n,n)相连的对角线,一共有多少条不同的路径?


    接下来,证明这个映射是一个双射,由于双射对应的集合的元素是一一对应的,那么(路径问题)中不同路径的条数也就等于原题中不同合法表达式的个数。证明如下:
    (表达式)--->(路径),对于每一个左括号(,我们在网格中往右走一步,对于每一个右括号,则向上走一步,例如表达式 ()(()(())(()))() 构造出来的路径就如上图所示。不同的表达式构造出不同的路径。由于合理的表达式中任意前m个括号中左括号的个数不能小于右括号的个数,对应在网格路径中,任意时刻向右的步数不得少于向上的步数,那么也就不会穿过(0,0)和(n,n)的连线。
    (路径)--->(表达式),同理,对于从(0,0)开始的路径,向右的一步记为左括号(,向上的路径记为右括号,所以上图中路径对应的表达式即为 ()(()(())(()))(). 由于路径不得穿过(0,0)和(n,n)的连线,那么任意时刻向右的步数不得少于向上的步数,所以左括号的个数不少于右括号的个数。同时由于向右的步数等于向上的步数,表明左右括号的个数相等,所以表达式是合理的。同样可以发现不同的路径构造出不同的表达式。
    所以,表达式问题和路径问题的解集合存在双射关系,他们的势相等,那么合理表达式的个数等于不同路径的条数。


    接下来,如何求路径问题的不同路径条数?
    先忽略“不穿过(0,0)和(n,n)相连的对角线”这个约束,那么在2n个步子中选择n个向右的步子的方法数,也即不同路径的条数是inom{2n}{n}.
    接下来,考虑原路径问题的反面:穿过(0,0)和(n,n)相连的对角线的路径条数,显然,这样的路径一定会在某个时刻到达某个(k,k+1)(0<k<n)点。那么就假设一条路径第一次穿过(0,0)和(n,n)相连的对角线之后到达(k,k+1)这个点,把这条路径分成(0,0)到(k,k+1)和(k,k+1)到(n,n)两段:
    (1) 从(0,0)到(k,k+1),也就是在(2k+1)个步子中选择k个向右,(k+1)个向上的;
    (2) 从(k,k+1)到(n,n),也就是在(2n-2k-1)个步子中选择(n-k)个向右,(n-k-1)个向上的。我们把从(k,k+1)到(n,n)的矩形旋转90度,在新图形中,需要从(k,k+1)到(n-1,n+1),也就是在(2n-2k-1)个步子中选择(n-k-1)个向右,(n-k)个向上的。注意这里旋转前后的路径条数是相等的。

    那么为什么要做这个旋转呢?首先根据上述分析,原网格中从(0,0)到(n,n)且过某个特定的(k,k+1)的路径条数(记为N_k^{	ext{ori}})和旋转后网格中从(0,0)到(n-1,n+1)且过同样的(k,k+1)的路径条数(记为N_k^{	ext{flip}})是相等的。由于对每个可能的k该结论都成立。所以综合所有的k有sum_k N_k^{	ext{ori}}=sum_k N_k^{	ext{flip}},等式左边等于原网格中穿过(0,0)和(n,n)相连的对角线(即经过其中某个(k,k+1))的路径条数,等式右边等于旋转后的网格中从(0,0)到(n-1,n+1)且经过其中某个(k,k+1)的路径条数。进一步可以发现,在旋转后的网格中,任意一条从(0,0)到(n-1,n+1)的路径都必然会经过某一个(k,k+1),所以等式右边也就等于从(0,0)到(n-1,n+1)的路径条数inom{2n}{n+1},即sum_k N_k^{	ext{ori}}=sum_k N_k^{	ext{flip}} = inom{2n}{n+1}.

    综上,原路径问题中,不穿过(0,0)和(n,n)的连线的路径条数即为inom{2n}{n}-inom{2n}{n+1}=frac{1}{n+1}inom{2n}{n}.




    其实,Catalan Number涉及的问题种类繁多,很多实际问题都可以归类其中,举几个例子(也可以参考Catalan Number Problems)。

    1. 序列问题(或投票问题)。确定一个长为2n的{0,1}序列,要求任意前k个数中,1的个数比0的个数多,求满足条件的序列个数。可以很容易发现,这个问题同路径问题也存在双射关系(1代表向右一步,0代表向上一步),所以答案也是C_n.

    2. 入栈出栈问题。见一个有趣的(由栈引发的)排列组合问题?

    3. 二叉树问题。有(n+1)个叶子的带根二叉树一共有多少个?最简单的方法是把这个问题双射到序列问题上。二叉树的非叶节点对应1,叶节点对应0,一个序列对应一棵二叉树的先序遍历序列。如下图的二叉树对应的序列为 11010011(注意由于有(n+1)个叶子的带根二叉树一共有(2n+1)个点,所以不考虑最后一个到达的叶节点),具体证明这里就不展开了,类似上面的方法。


    4. 凸多边形切割问题。给定一个(n+2)条边的凸多边形,连接对角线将该多边形分为若干个三角形,一共有多少种分法?这个问题可以直接从二叉树问题中衍生出来,见下图。

    5. 握手问题。2n个人均匀坐在一个圆桌边上,某个时刻所有人同时与另一个人握手,要求手之间不能交叉,求一共有多少种握手方法。双射到表达式问题:从某一个人出发,沿着某一个方向依次将每个人替换成左括号或右括号,如果一个人没有与之前的人握手,那么标记为左括号,否则标记为右括号。同样,证明略去。

    .......

    这些问题的证明或者求解思路基本都是利用双射将解集合映射到一个已知个数为Catalan Number的问题的解集合上。这种方法英文叫做Bijection,是组合数学里面非常常用也有用的证明方法。

  • 相关阅读:
    网络测量中基于Sketch方法的简单介绍
    Reading SBAR SDN flow-Based monitoring and Application Recognition
    Reading Meticulous Measurement of Control Packets in SDN
    Reading SketchVisor Robust Network Measurement for Sofeware Packet Processing
    ovs加dpdk在日志中查看更多运行细节的方法
    后缀数组
    (转载)LCA问题的Tarjan算法
    Codeforces Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) A. Checking the Calendar(水题)
    Vijos 1816统计数字(计数排序)
    卡特兰数
  • 原文地址:https://www.cnblogs.com/Roni-i/p/8418578.html
Copyright © 2011-2022 走看看