8.14.7 ACM-ICPC 组合数学 卡特兰数

8.14.7 ACM-ICPC 组合数学 卡特兰数

引言

卡特兰数(Catalan Number)是组合数学中一个重要的数列,在很多不同的组合问题中都有出现。它们在ACM-ICPC竞赛中也经常被用于解决各种复杂的问题。本节将详细介绍卡特兰数的定义、性质以及应用。

卡特兰数的定义

卡特兰数是一列自然数,通常用C_n表示。卡特兰数的递推公式为:

其中,C_0 = 1。卡特兰数也可以通过二项式系数表示:

卡特兰数的性质

卡特兰数有许多有趣的性质和组合解释,其中一些主要性质包括:

  1. 递归关系:如上所示,卡特兰数可以通过递归公式进行计算。
  2. 生成函数:卡特兰数的生成函数为:

  1. 多项式表示:卡特兰数可以通过多项式表示,使其在组合数学中具有广泛的应用。

卡特兰数的应用

卡特兰数在许多组合问题中都有应用,以下是几个典型的例子:

  1. 括号匹配问题:有n对括号,有多少种合法的括号匹配方式?
  2. 二叉树问题:有n个节点的不同二叉树的数量。
  3. 凸多边形的三角剖分:有n+2个顶点的凸多边形可以分成多少个三角形。

Catalan 数列

Catalan 数列 H_n 可以应用于以下问题:

  1. 剧场排队问题:有 2n 个人排成一行进入剧场。入场费 5 元。其中只有 n 个人有一张 5 元钞票,另外 n 人只有 10 元钞票,剧院无其它钞票,问有多少种方法使得只要有 10 元的人买票,售票处就有 5 元的钞票找零?
  2. 方格路径问题:有一个大小为 n×n 的方格图,左下角为 (0, 0) 右上角为 (n, n),从左下角开始每次都只能向右或者向上走一单位,不走到对角线 y=x 上方(但可以触碰)的情况下到达右上角有多少可能的路径?
  3. 圆上不相交线段问题:在圆上选择 2n 个点,将这些点成对连接起来使得所得到的 n 条线段不相交的方法数?
  4. 凸多边形三角剖分问题:对角线不相交的情况下,将一个凸多边形区域分成三角形区域的方法数?
  5. 栈出栈序列问题:一个栈(无穷大)的进栈序列为 1,2,3,...,n 有多少个不同的出栈序列?
  6. 不同二叉树问题:n 个结点可构造多少个不同的二叉树?
  7. 特定部分和问题:由 n 个 +1 和 n 个 -1 组成的 2n 个数 a_1,a_2,...,a_{2n},其部分和满足 a_1+a_2+...+a_k ≥ 0 (k=1,2,3,...,2n),有多少个满足条件的数列?

其对应的序列为:

H_0H_1H_2H_3H_4H_5H_6...
11251442132...

递推式

该递推关系的解为:

关于 Catalan 数的常见公式:

例题 洛谷 P1044 栈

题目大意:入栈顺序为 1,2,...,n,求所有可能的出栈顺序的总数。

#include <iostream>
using namespace std;
int n;
long long f[25];

int main() {
  f[0] = 1;
  cin >> n;
  for (int i = 1; i <= n; i++) f[i] = f[i - 1] * (4 * i - 2) / (i + 1);
  // 这里用的是常见公式2
  cout << f[n] << endl;
  return 0;
}

封闭形式

卡特兰数的递推式为:

其中 H_0=1, H_1=1。设它的普通生成函数为 H(x)。

我们发现卡特兰数的递推式与卷积的形式很相似,因此我们用卷积来构造关于 H(x) 的方程:

解得:

那么这就产生了一个问题:我们应该取哪一个根呢?我们将其分子有理化:

代入 x=0,我们得到的是 H(x) 的常数项,也就是 H_0。当:

的时候有 H(0)=1,满足要求。而另一个解会出现分母为 0 的情况(不收敛),舍弃。

因此我们得到了卡特兰数生成函数的封闭形式:

接下来我们要将其展开。但注意到它的分母不是斐波那契数列那样的多项式形式,因此不方便套用等比数列的展开形式。在这里我们需要使用牛顿二项式定理。我们来先展开 1−4x\sqrt{1-4x}1−4x​:

注意到:

这里使用了双阶乘的化简技巧。那么带回得到:

带回原式得到:

这样我们就得到了卡特兰数的通项公式。

实例分析

以下是一个使用卡特兰数解决括号匹配问题的例子:

def catalan_number(n):
    if n == 0 or n == 1:
        return 1
    catalan = [0] * (n + 1)
    catalan[0], catalan[1] = 1, 1
    for i in range(2, n + 1):
        for j in range(i):
            catalan[i] += catalan[j] * catalan[i - 1 - j]
    return catalan[n]

# 计算第5个卡特兰数
n = 5
print(f"第{n}个卡特兰数是: {catalan_number(n)}")

输出结果:

第5个卡特兰数是: 42

总结

卡特兰数是组合数学中的一个重要数列,广泛应用于括号匹配、二叉树计数和多边形三角剖分等问题。通过掌握卡特兰数的性质和应用,可以更好地解决ACM-ICPC竞赛中的组合数学问题。在实际应用中,递归和动态规划是计算卡特兰数的两种主要方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值