zoukankan      html  css  js  c++  java
  • Catalan数应用整理

    应用一:

    codevs 3112 二叉树计数

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 黄金 Gold
     
    题目描述 Description

    一个有n个结点的二叉树总共有多少种形态

    输入描述 Input Description

    读入一个正整数n

    输出描述 Output Description

    输出一个正整数表示答案

    样例输入 Sample Input

    6

    样例输出 Sample Output

    132

    数据范围及提示 Data Size & Hint

    1<=n<=20

     1 #define N 25
     2 #include<cstdio>
     3 #include<iostream>
     4 using namespace std;
     5 long long f[N];
     6 int main()
     7 {
     8     int n;
     9     scanf("%d",&n);
    10     f[0]=1;f[1]=1;
    11     for(int i=2;i<=n;++i)
    12       for(int k=0;k<i;++k)
    13       f[i]+=f[k]*f[i-1-k];
    14     printf("%d
    ",f[n]);
    15     return 0;
    16 }

    下面解释:为什么n个节点的二叉树的形态数目是Catalan数?

     1 /*
     2 先考虑只有一个节点的情形,设此时的形态有f(1)种,那么很明显f(1)=1
     3 
     4 如果有两个节点呢?我们很自然想到,应该在f(1)的基础上考虑递推关系。那么,如果固定一个节点后,有两种情况,一是左子树还剩一个节点,此刻类型数量为f(1),第二种情况是右子树生一个节点,此刻类型数量为f(1),固有f(2) = f(1) + f(1)
     5 
     6 如果有三个节点呢?我们需要考虑固定两个节点的情况么?当然不行,为什么?
     7 
     8 因为当节点数量大于等于2时,无论你如何固定,其形态必然有多种,而在这多种基础之上你如何安排后续剩下的节点呢?所以必须挑出这个误区。
     9 
    10 回到二叉树的定义,二叉树本质上就是一个递归的形式,左子树,右子树,根节点。所以根节点应该不变,需要递归处理的是左右子树。
    11 
    12 也就是说,还是考虑固定一个节点,即根节点。好的,按照这个思路,还剩2个节点,那么左右子树的分布情况为2=0+2=1+1=2+0。
    13 
    14 所以有3个节点时,递归形式为f(3)=f(2) + f(1)*f(1) + f(2). (注意这里的乘法,因为左右子树一起组成整棵树,根据排列组合里面的乘法原理即可得出)
    15 
    16 那么有n个节点呢?我们固定一个节点,那么左右子树的分布情况为n-1=n-1 + 0 = n-2 + 1 = ... = 1 + n-2 = 0 + n-1
    17 
    18 OK。递归表达式出来了f(n) = f(n-1) + f(n-2)f(1) + f(n-3)f(2) + ... + f(1)f(n-2) + f(n-1)
    19 
    20  
    21 
    22 观察一下这个表达式,嗯,和我们之前见过的递归表达有一点区别,递推层级为n的时候,更多的是考虑前一步(n-1),或者前两步(n-1)和(n-2)。
    23 
    24 但是这里却考虑到所有的情况,即1到n-1。
    25 
    26 最后说明一下,这个表达式有一个学名,叫做Catalan数。上面我们没有定义f(0)。如果把f(0)也考虑进去,显然没有节点也只有一种情况,即f(0)=1
    27 
    28 标准表达式为f(n) = f(n-1)f(0) + f(n-2)f(1) + f(n-3)f(2) + ... + f(1)f(n-2) + f(n-1)f(0)
    29 
    30 前几个数为1,1,2,5,14,42,132。
    31 */

    应用二:

    codevs 3134 Circle 

     时间限制: 1 s
     空间限制: 32000 KB
     题目等级 : 黄金 Gold
     
    题目描述 Description

    在一个圆上,有2*K个不同的结点,我们以这些点为端点,连K条线段,使得每个结点都恰好用一次。在满足这些线段将圆分成最少部分的前提下,请计算有多少种连线的方法

    输入描述 Input Description

    仅一行,一个整数K(1<=K<=30)

    输出描述 Output Description

    两个用空格隔开的数,后者为最少将圆分成几块,前者为在此前提下连线的方案数

    样例输入 Sample Input

    2

    样例输出 Sample Output

    2 3

    数据范围及提示 Data Size & Hint
     1 #include<cstdio>
     2 int n;
     3 long long f;
     4 int main()
     5 {
     6     scanf("%d",&n);
     7     f=1;
     8     for(int i=2;i<=n;++i)
     9     f=f*(4*i-2)/(i+1);
    10     printf("%lld %d",f,n+1);
    11 /*最少的划分部分是n条线段都不相交*/
    12     return 0;
    13 }
  • 相关阅读:
    ans_rproxy 说明
    ubuntu adduser
    linux 修改 elf 文件的dynamic linker 和 rpath
    What Is The Promiscuous Mode
    gpart 分区工具
    TortoiseSVN的基本使用方法
    svn和git的区别及适用场景
    TortoiseSVN 和 VisualSVN Server 使用教程
    SVN中trunk、branches、tag的使用
    C/C++中substr函数的应用(简单讲解)
  • 原文地址:https://www.cnblogs.com/c1299401227/p/6065720.html
Copyright © 2011-2022 走看看