Catalan数应用

Catalan数应用

  • Catalan数应用
    • 原理
    • 卡特兰数经典应用
      • 括号化
      • 买票找零
      • 组合数与阶乘计算

卡特兰数又称卡塔兰数,是组合数学中一个常出现在各种计数问题中的数列。由以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)命名。
其前几项为 : 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, … Catalan数是许多计数问题的最终形式。

原理

  • 令h(0)=1,h(1)=1,catalan数满足递推式:
    h(n)=h(0)h(n1)+h(1)h(n2)+...+h(n1)h(0)(n>=2)

  • 另类递推公式:

    1. h(n)=h(n1)(4n2)/(n+1)
    2. x=(2nn)n+1(n=0,1,2,)
    3. h(n)=(2nn)(2nn1)(n=0,1,2,)

公式中 (nm)=n!(nm)!

卡特兰数经典应用

括号化

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

思路:可以这样考虑,首先通过括号化,将公式分成两个部分,然后分别对两个部分进行括号化。比如分成 (a1)×(a2×a3××an) ,然后再对 (a1) (a2×a3××an) 分别括号化;又如分成 (a1×a2)×(a3××an) ,然后再对 (a1×a2) (a3××an) 括号化;以此类推,得公式

f(n)=f(1)f(n1)+f(2)f(n2)+f(3)f(n3)++f(n1)f(1)

f(1) = 1, f(2) = 1, f(3) = 2, f(4) = 5,结合递归式,不难发现f(n)=h(n-1)。

买票找零

原题描述如下:

2n个人排队买票,其中n个人持50元,n个人持100元。每张票50元,且一人只买一张票。初始时售票处没有零钱找零。请问这2n个人一共有多少种排队顺序,不至于使售票处找不开钱?

思路:队伍的序号标为0,1,…,2n-1,并把50元看作左括号,100元看作右括号,合法序列即括号能完成配对的序列。对于一个合法的序列,第0个一定是左括号,它必然与某个右括号配对,记其位置为k。那么从1到k-1、k+1到2n-1也分别是两个合法序列。那么,k必然是奇数(1到k-1一共有偶数个),设k=2i+1。那么剩余括号的合法序列数为f(2i)*f(2n-2i-2)个。取i=0到n-1累加即可。

f(2n)=i=0n1f(2i)f(2n2i2)(n1)

f(0)=0 , (00)=0 ,即可得

f(2n)=(2nn)n+1(n1)

公式推导如下,出自从《编程之美》买票找零问题说起,娓娓道来卡特兰数——兼爬坑指

构造生成函数:

g(x)=h0x2+h2x4++h2n2x2n+h2nx2n+2+

其中 h2n=f(2n)=n1i=0f(2i)f(2n2i2)(n1)

生成函数平方:

[g(x)]2==h0x2+h2x4++h2n2x2n+h2nx2n+2+h20x4+(h0h2+h2h0)x6++(h0h2n2+h2h2n4++h2n2h0)x2n+2+

则:

[g(x)]2g(x)=h20x4h2x4h0x2

对于题目,假设 h0=f(0)=0 ,则根据递推公式后续项全为0,不合题意,那么 h0=f(0)=1 ,可以推出 h2=f(2)=1 ,带入公式,则有:

[g(x)]2g(x)+x2=0

解得 g(x)=1±14x22
根据生成函数的各项系数为非负,舍去其一,在根据

(1+z)1/2=1+n=1(1)n1n×22n1(2n2n1)zn

可以得到

g(x)=n=11n(2n2n1)x2n

h2n=1n+1(2nn)

组合数与阶乘计算

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import operator

'''factorial function:阶乘函数;也可用math.factorial'''
def factorial(n):
    return reduce(operator.mul, range(1, int(n+1)));

'''combinational calculation:组合计算'''
def comb(n, m):
    return reduce(operator.mul, range(n-m+1, n+1)) / factorial(m)

'''calculation on the arrangement:排列组合计算'''
def arr(n, m):
    return factorial(n) / factorial(n-m)

if __name__ == "__main__":
    print factorial(10)
    print comb(6,3)
    print arr(10,7)

参考:

  • http://www.cnblogs.com/wuyuegb2312/p/3016878.html

你可能感兴趣的:(卡特兰数,组合排序)