数学 ( 卡特兰数 )——Scoop water ( CSU 1320 )

  • 题目链接:
    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1320

  • 分析:
    问题可以转化成求含有n个0和n个1的长度为2n的01串中,从左往右扫时,在每一个位置经过的0不多与1的串01串的个数。
    这是一道关于卡特兰(Catalan)数的问题。

  • 题解:

    • Catalan数的原理
      令h(0)=1,h(1)=1,catalan数满足递推式[1] :
      h(n)=h(0)h(n1)+h(1)h(n2)+..+h(n1)h(0)(n>=2)
      例如:
      h(2)=h(0)×h(1)+h(1)×h(0)=1×1+1×1=2
      h(3)=h(0)×h(2)+h(1)×h(1)+h(2)×h(0)=1×2+1×1+2×1=5
      另类递推式:
      h(n)=h(n1)×(4×n2)/(n+1);
      递推关系的解为:
      h(n)=C(2n,n)/(n+1)(n=0,1,2,...)
      递推关系的另类解为:
      h(n)=C(2n,n)C(2n,n1)(n=0,1,2,...)
    • Catalan数的应用:

      1. 括号化
        矩阵连乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n-1)种)

      2. 出栈次序
        首先,我们设f(n)=序列个数为n的出栈序列种数。(我们假定,最后出栈的元素为k,显然,k取不同值时的情况是相互独立的,也就是求出每种k最后出栈的情况数后可用加法原则,由于k最后出栈,因此,在k入栈之前,比k小的值均出栈,此处情况有f(k-1)种,而之后比k大的值入栈,且都在k之前出栈,因此有f(n-k)种方式,由于比k小和比k大的值入栈出栈情况是相互独立的,此处可用乘法原则,f(n-k)*f(k-1)种,求和便是Catalan递归式。(h(n))

      3. 凸多边形三角划分
        在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。任务是键盘上输入凸多边形的边数n,求不同划分的方案数f(n)。比如当n=6时,f(6)=14。
        因为凸多边形的任意一条边必定属于某一个三角形,所以我们以某一条边为基准,以这条边的两个顶点为起点P1和终点Pn(P即Point),将该凸多边形的顶点依序标记为P1、P2、……、Pn,再在该凸多边形中找任意一个不属于这两个点的顶点Pk(2<=k<=n-1),来构成一个三角形,用这个三角形把一个凸多边形划分成两个凸多边形,其中一个凸多边形,是由P1,P2,……,Pk构成的凸k边形(顶点数即是边数),另一个凸多边形,是由Pk,Pk+1,……,Pn构成的凸n-k+1边形。
        此时,我们若把Pk视为确定一点,那么根据乘法原理,f(n)的问题就等价于——凸k多边形的划分方案数乘以凸n-k+1多边形的划分方案数,即选择Pk这个顶点的f(n)=f(k)×f(n-k+1)。而k可以选2到n-1,所以再根据加法原理,将k取不同值的划分方案相加,得到的总方案数为:f(n)=f(2)f(n-2+1)+f(3)f(n-3+1)+……+f(n-1)f(2)。看到此处,再看看卡特兰数的递推式,答案不言而喻,即为f(n)=h(n-2) (n=2,3,4,……)。

      4. 给定节点组成二叉搜索树
        给定N个节点,能构成多少种不同的二叉搜索树?
        (能构成h(N)个)
        (这个公式的下标是从h(0)=1开始的)

      5. 对于在n位的2进制中,有m个0,其余为1的catalan数为:C(n,m)-C(n,m-1)。

    • Catalan数计算代码:

 //递归求法,耗空间都是从0开始
unsigned long long catalannumber1(int n) 
{  
    if(n == 0)  
        return 1;  
    else  
        return (4 * n - 2) * catalannumber1(n-1) / (n + 1);  
}  
//递推求法,耗时间
unsigned long long catalannumber2(int n)  
{  
    unsigned long long cn = 1;  
    int i;  

    for(i=1; i<=n; i++)  
        cn = (4 * i - 2) * cn / (i + 1);  

    return cn;  
}  
//递推法求,(存储之前的数据),省时间
long long f[10005];
int n;
const int mod=1000000007;
int main()
{
    f[0]=1;
    for(int i=1;i<=10000;i++)
        for(int j=0;j<i;j++)
    f[i]=((f[j]*f[i-1-j])%mod+f[i])%mod;

    while(scanf("%d",&n)!=EOF)
    {
        printf("%lld\n",f[n]);
    }
    return 0;
}
  • 一组卡特兰数
    0: 1,
    1: 1,
    2: 2,
    3: 5,
    4:14,
    5:42,
    6:132,
    7:429,
    8:1430,
    9:4862,
    10:16796,
    11:58786,
    12:208012,
    13:742900,
    14:2674440,
    15:9694845,
    16:35357670,
    17:129644790,
    18:477638700,
    19:1767263190,
    20:6564120420,
    21:24466267020,
    22:91482563640,
    23:343059613650,
    24:1289904147324,
    25:4861946401452,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值