首页 > 其他分享 >卡特兰数专题(Catalan)

卡特兰数专题(Catalan)

时间:2023-11-29 11:32:11浏览次数:32  
标签:专题 frac int len times Catalan 2n 卡特兰

卡特兰数专题(\(Catalan\))

一、什么是卡特兰数?

明安图数,又称卡塔兰数,英文名\(Catalan\) \(number\),是组合数学中一个常出现于各种计数问题中的数列。以中国蒙古族数学家明安图 \((1692-1763)\)和比利时的数学家欧仁·查理·卡塔兰 \((1814–1894)\)的名字来命名,其前几项为(从第零项开始) : \(1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862,16796, 58786 …\)

知乎 卡特兰数四连击

https://zhuanlan.zhihu.com/p/31317307

https://zhuanlan.zhihu.com/p/31526354

https://zhuanlan.zhihu.com/p/31585260

https://zhuanlan.zhihu.com/p/31050581

卡特兰数的几何意义

简单来说,卡特兰数就是一个有规律的数列,在坐标图中可以表示为:从原点\((0,0)\)出发,每次向\(x\)轴或者\(y\)轴正方向移动\(1\)个单位,直到到达\((n,n)\)点,且在移动过程中不越过第一象限平分线的移动方案总数。

卡特兰数专题(Catalan)_卡特兰数

卡特兰数公式推导

我们暂且先不考虑移动过程中不越过第一象限平分线这个约束条件,那么从\((0,0)\)点到\((n,n)\)点的过程中,我们总共需要向右移动\(n\)步,向上移动\(n\)步,一共\(2n\)步。我们可以理解为在\(2n\)步里面选出\(n\)步来向上移动,那么剩下的\(n\)步就是向右移动的步数,那么方案总数就是\(\LARGE \displaystyle C_{2n}^{n}\)

现在,我们来看看如何解决不越过第一象限平分线这个问题。仔细想想,不越过第一象限平分线也就等价于不触碰到\(y = x + 1\)这条直线。而我们如果把触碰到了直线\(y = x + 1\)的路线的第一个与\(y = x + 1\)的触碰点之后的路线关于直线\(y = x + 1\)对称,并画出对称后的路线

卡特兰数专题(Catalan)_卡特兰数_02

黄海解读

卡特兰数专题(Catalan)_i++_03

我们会发现触碰到了直线\(y = x + 1\)的路径的终点都变成了点\((n-1,n+1)\)。也就是说,从\((0,0)\)点到\((n,n)\)点的路线当中触碰了直线\(y = x + 1\)的路线条数与从\((0,0)\)点到\((n-1,n+1)\)点的路线条数的数量是相等的。于是从\((0,0)\)点到\((n,n)\)点的非法路径条数为\(\LARGE \displaystyle C_{2n}^{n-1}\)

综上所述,从\((0,0)\)点到\((n,n)\)点满足条件的路径数为

卡特兰数通项公式I

$$\huge f(n)=C_{2n}{n}-C_{2n}$$

通过化简,公式可以简化为:

\[\large Catalan_n= C_{2n}^{n}-C_{2n}^{n-1}=\frac{(2n)!}{n! \times n!}-\frac{(2n)!}{(n+1)!\times (n-1)!} \\ =\frac{(2n)!\times (n+1)}{n!\times (n+1)!}-\frac{(2n)!\times n}{n! \times (n+1)!} \\ =\frac{(2n)!\times (n+1)-(2n)!\times n}{n!\times (n+1)!} \\ =\frac{(2n)!}{n!\times (n+1)!}=\frac{1}{n+1}\times \frac{(2n)!}{n!\times n!}  =\frac{C_{2n}^n}{n+1}
\]

卡特兰数通项公式II

$$\huge \displaystyle f(n)=\frac{C_{2n}^n}{n+1} $$

除了这个通项公式之外,卡特兰数还有一个由该通项公式推导而来的递推公式:

\(\large \displaystyle Catalan_{n+1}= \frac{1}{n+2}C_{2n+2}^{n+1} \\
=\frac{1}{n+2}\times \frac{(2n+2)!}{(n+1)!\times (n+1)!} \\
=\frac{1}{n+2}\times \frac{(2n)!\times (2n+1) \times (2n+2)}{n! \times n!\times (n+1)^2} \\
=\frac{1}{n+2}\times \frac{(2n+1)\times(2n+2)}{n+1} \times \frac{1}{n+1} \times \frac{(2n)!}{n!\times n!} \\
=\frac{2(2n+1)}{n+2}\times \frac{1}{n+1}\times C_{2n}^n \\
=\frac{4n+2}{n+2}Catalan_n
\)

初始值:f[0] = f[1] = 1

卡特兰数公式III(递推)

$$\huge f(n)=\frac{4n-2}{n+1}f(n-1) $$

卡特兰数公式IV(取模常用)

$$ \huge f(n)=\frac{(2n)!}{(n+1)! \times n!} $$

卡特兰数公式V(递推)

一般不用来实现,用来推规律

$$\huge \displaystyle f(n)=\sum_{i=0}^{n-1}f(i)f(n-i-1) $$

证明:在\(n\)对括号的排列中,假设最后一个括号和第\(i\)个左括号匹配。则在第\(i\)个左括号之前,一定已经匹配上了(\(i-1\))对左括号。如下图,因此,此种情况的数量为\(f(i-1)*f(n-i)\)。(\(1<=i<=n\))最后一个右括号可以\(1\sim n\)个左括号匹配共\(n\)种情况。

卡特兰数专题(Catalan)_出栈_04

因此,对\(i\)从\(1\)到\(n\)的情况求和得到\(\large \displaystyle f(n)=\sum_{i=0}^{n-1}f(i)f(n-i-1)\),即可得到递推公式。

二、常见考点

1、 进出栈问题

设栈\(S\)的初始状态为空,元素\(a,b,c,d,e\)依次入栈,以下出栈序列有多少种可能性注意:这个序列顺序是定的.

重点:归纳法思考,由大及小。

我们这样去想,假设最终的出栈序列可能性用\(f(n)\)表示,其中\(n\)就是元素的个数。

假设第\(k\)个数是最后出栈的数,那么:

  • 比它小的前\(k-1\)个数,肯定已经完成了入栈,出栈操作。因为从逻辑顺序上来讲,它们无法压到\(k\)下面去吧。
  • 比它大的后\(n-k\)个数,肯定已经完成了入栈,出栈操作。它们倒是可以压到\(k\)下面去,但假设\(k\)是最后一个出栈的,它们不能破坏掉假设,也必须提出出栈。

现在,\(k\)将原来的问题,划分为两个子问题\(f(n-k)\)和\(f(k-1)\),根据乘法原理,结果就是\(f(n-k)*f(k-1)\)。

\(k\)的取值范围是\(1 \leq k \leq n\),再根据加法原理:

\[\large f(n)=\sum_{k=1}^{n}f(n-k)\times f(k-1) \]

展开写就是:$$\large f(n)=f(0) \times f(n-1) + f(1) \times f(n-2) + ... +f(n-1)\times f(0)$$

代码实现:

f[0] = 1;
for (int i = 1; i <= 12; i++) {
    int fi = 0;
    for (int j = 0; j <= i - 1; j++) fi += f[j] * f[i - j - 1];
    cout << fi << " ";
}

P1044 [NOIP2003 普及组] 栈

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 20;
int f[N];
int main() {
    int n;
    cin >> n;
    f[0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= i; j++)
            f[i] += f[j - 1] * f[i - j];
    cout << f[n] << endl;
    return 0;
}

2、排队问题

变种(排队问题):出栈入栈问题有许多的变种,比如\(n\)个人拿\(5\)元、\(n\)个人拿\(10\)元买物品,物品\(5\)元,老板没零钱。问有几种排队方式。熟悉栈的同学很容易就能把这个问题转换为栈。值得注意的是,由于每个拿\(5\)元的人排队的次序不是固定的,所以最后求得的答案要\(n!\)。拿\(10\)元的人同理,所以还要\(n!\)。所以这种变种的最后答案为\(h(n)*n!\)。
P1754 球迷购票问题

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 30;
LL f[N];
int main() {
    int n;
    cin >> n;
    f[0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= i; j++)
            f[i] += f[j - 1] * f[i - j];
    cout << f[n] << endl;
    return 0;
}

3、 二叉树构成问题

有\(n\)个结点,问总共能构成几种不同的二叉树。

我们可以假设,如果采用中序遍历的话,根结点第\(k\)个被访问到,则根结点的左子树有\(k-1\)个点、根结点的右指数有\(n-k\)个点。\(k\)的取值范围为\(1\)到\(n\)。讲到这里就很明显看得出是卡特兰数了。

AcWing 1645. 不同的二叉搜索树 没有超过\(long\) \(long\)的存储范围的话,可以使用递推;

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 1010, MOD = 1e9 + 7;

int n;
int f[N];

int main() {
    cin >> n;

    f[0] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= i; j++)
            f[i] = (f[i] + (LL)f[j - 1] * f[i - j]) % MOD;

    cout << f[n] << endl;
    return 0;
}

AcWing 1317. 树屋阶梯 模拟,按照公式(1)进行模拟,需要使用高精度
黄海的题解

AcWing 1257. 二叉树计数

#include <bits/stdc++.h>
using namespace std;

const int N = 10010; // 5000*2+10
int primes[N], cnt;
bool st[N];
int a[N], b[N];

void get_primes(int n) {
    for (int i = 2; i <= n; i++) {
        if (!st[i]) primes[cnt++] = i;
        for (int j = 0; primes[j] * i <= n; j++) {
            st[i * primes[j]] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

int get(int n, int p) { // n!中p的次数
    int s = 0;
    while (n) n /= p, s += n;
    return s;
}

void mul(int a[], int b, int &len) {
    int t = 0;
    for (int i = 1; i <= len; i++) {
        t += a[i] * b;
        a[i] = t % 10;
        t /= 10;
    }
    while (t) {
        a[++len] = t % 10;
        t /= 10;
    }
    //去前导0
    while (len > 1 && !a[len]) len--;
}

int C(int a, int b, int c[]) {
    int len = 1;
    c[1] = 1;
    for (int i = 0; i < cnt; i++) {
        int p = primes[i];
        int s = get(a, p) - get(b, p) - get(a - b, p);
        while (s--) mul(c, p, len);
    }
    return len;
}

void sub(int a[], int b[], int &len) {
    int t = 0;
    for (int i = 1; i <= len; i++) {
        t = a[i] - b[i] - t;
        a[i] = (t + 10) % 10;
        t < 0 ? t = 1 : t = 0;
    }
    while (len > 1 && !a[len]) len--;
}

int main() {
    //加快读入
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    get_primes(N - 10);

    int n;
    cin >> n;
    int a1 = C(n + n, n, a);
    int b1 = C(n + n, n - 1, b); // bl下面没有用到,原因是两数相减,我们知道a>b,按着a的长度来就行了

    sub(a, b, a1);

    for (int i = a1; i >= 1; i--) printf("%d", a[i]);
    return 0;
}

4、\(01\)序列

给出一个\(n\),要求一个长度为\(2n\)的\(01\)序列,使得序列的任意前缀中\(1\)的个数不少于\(0\)的个数,有多少个不同的\(01\)序列?

以下为长度为\(6\)的序列:
111000 101100 101010 110010 110100

类比一下括号问题,此题就是一个祼的卡特兰数问题。

5、\(+1\) \(-1\)序列

\(n\)个\(+1\)和\(n\)个\(-1\)构成的\(2n\)项 \(a_1,a_2,···,a_{2n}\) ,其部分和满足非负性质,即\(a_1+a_2+···+a_k>=0,(k=1,2,···,2n)\)

此典例解析与\(01\)序列解析一模一样,即此数列的个数等于第\(n\)个\(Catalan\)数,此处就不再赘述。

6、凸多边形划分

在一个\(n\)边形中,通过不相交于\(n\)边形内部的对角线,把\(n\)边形拆分为若干个三角形,问有多少种拆分方案?

如五边形有如下\(5\)种拆分方案:

卡特兰数专题(Catalan)_卡特兰数_05

如六边形有如下14种拆分方案:

卡特兰数专题(Catalan)_i++_06

结论:对凸\(n\)边形进行不同的三角形分割(只连接顶点对形成\(n\)个三角形)数为\(h[n-2]\)

这也是非常经典的一道题。我们可以这样来看,选择一个 基边 ,显然这是多边形划分完之后某个三角形的一条边。图中我们假设基边是\(p_1,p_n\),我们就可以用 \(p_1,p_n\) 和另外一个点假设为\(p_i\)做一个三角形,并将多边形分成三部分(要是\(i\)与\(1,n\)挨着的话,就是两部分),除了中间的三角形之外,一边是\(i\)边形,另一边是\(n−i+1\)边形。\(i\)的取值范围是\(2\)到\(n−1\)。所以本题的解

\[\large c(n)=c(2)*c(n−1)+c(3)*c(n−2)+...c(n−1)*c(2) \]

令\(f(i)=c(i+2)\)则

\[\large f(i)=f(0)f(i−1)+f(1)f(i−2)...+f(i−1)f(0) \]

很明显,这就是一个卡特兰数了。

卡特兰数专题(Catalan)_出栈_07

四、链接资源

五、递推与递归的代码实现

#include <bits/stdc++.h>

using namespace std;
const int N = 10;

// 学习视频
// https://www.bilibili.com/video/BV1nE411A7ST
int g[N];

// 递归
int f(int n) {
    if (n == 0 || n == 1) return 1;
    int sum = 0;
    // f(0)*f(n-1)+f(1)*f(n-2)+....+f(n-1)*f(0)
    for (int i = 0; i < n; i++)
        sum += f(i) * f(n - 1 - i);
    return sum;
}
int main() {
    // 1、递推法
    g[0] = g[1] = 1;
    for (int i = 2; i < N; i++)
        for (int j = 0; j < i; j++)
            g[i] += g[j] * g[i - j - 1]; // 考虑思路:画括号法

    for (int i = 0; i < N; i++)
        cout << g[i] << endl;

    // 2 、递归法
    for (int i = 0; i < N; i++)
        cout << f(i) << endl;
    return 0;
}



标签:专题,frac,int,len,times,Catalan,2n,卡特兰
From: https://blog.51cto.com/u_3044148/8613084

相关文章

  • 【专题】2023社群电商爆品营销白皮书报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=34389原文出处:拓端数据部落公众号2023年是全球电商市场复苏的一年,也是充满机遇和激烈竞争的一年。对于出海电商品牌来说,在避免"内卷"的同时,寻找创新和可持续的经营策略和营销方法将变得至关重要。在新的出海环境下,由于其品效兼备的价值,"爆品"将展......
  • 【专题】2023年中国手术机器人行业专题报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=34144仿生机器人作为一类结合了仿生学原理的机器人,具备自主决策和规划行动的能力,正逐渐进入大众视野。它们的核心技术要素包括感知与认知技术、运动与控制技术、人机交互技术和自主决策技术。阅读原文,获取专题报告合集全文,解锁文末68份仿生机器人......
  • 【专题】2023快手母婴行业数据报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=33866原文出处:拓端数据部落公众号品牌一直在思考如何更好地了解消费者的需求,特别是在年轻化和线上消费趋势加强的母婴行业。根据《2023母婴行业数据报告合集》,短视频直播平台成为该行业新的增长点。报告合集显示,母婴商品的消费人数在2022年全年和2......
  • 【专题】展望人工智能银行:当银行遇到AI报告PDF合集分享(附原数据表)
    报告链接:http://tecdat.cn/?p=32210在2016年,AlphaGo机器人打败了18届世界棋王李世石,成为了世界棋坛上最伟大的人物。阅读原文,获取专题报告全文,解锁154份文末人工智能银行相关报告。围棋是一种非常复杂的棋类,它要求有很强的直觉,想像力和策略性的思考,而这一切在很长一段时间里都......
  • 【Linux专题】同个ip同个服务器搭建多个站点https
    原创: 厦门微思网络Nginx配置文件多站点https配置文件如下:worker_processes4;events{worker_connections100000;}http{includemime.types;default_typeapplication/octet-stream;sendfileon;tcp_nopushon;tcp_nodelayon;keepalive_......
  • Terraform专题精讲——为什么使用 Terraform
    为什么使用Terraform一、什么是基础设施即代码?https://aws.amazon.com/cn/what-is/iac/ 亚马逊AWS最早提出了基础设施即代码(InfrastructureasCode,简称IaC)的概念。基础设施即代码(IaC)是指使用代码而不是手动流程和设置来配置和支持您的计算基础设施的能力。任何应用程序环......
  • 【专题】2023年中国社会办口腔医疗企业报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=34300原文出处:拓端数据部落公众号口腔健康是整体健康的重要基石,当前,无论是哪个年龄段的人群,或多或少都会受到口腔问题的困扰。随着国民口腔健康意识的不断提高,消费者对口腔医疗服务的需求日益多元化,口腔医疗行业也迎来了快速发展阶段。阅读原文,获......
  • 【专题】2022年中国跨境电商行业研究报告PDF合集分享(附原数据表)
    报告链接:http://tecdat.cn/?p=32044近年来,我国的跨境电子商务发展迅速,在过去五年中,其贸易额增长率达到了16.2%,已经成为稳定对外贸易的一支重要力量。阅读原文,获取专题报告合集全文,解锁文末52份跨境电商行业相关报告。一方面,随着跨境电子商务的发展,跨境电子商务的监管政策得到了......
  • c++线程专题
    逐步更新中~~~,参考书籍《C++并发编程实战(第2版)》,不照搬书,只写理解感悟。引入头文件#include<thread>线程启动std::threadt(my_func);若需等待线程执行完毕,才继续之后的代码,用joinif(t.joinable()){t.join();}若不等待,可以分离出去(分离出去的线程被称为守护......
  • 【专题】2023快手母婴行业数据报告PDF合集分享(附原数据表)
    品牌一直在思考如何更好地了解消费者的需求,特别是在年轻化和线上消费趋势加强的母婴行业。根据《2023母婴行业数据报告合集》,短视频直播平台成为该行业新的增长点。报告合集显示,母婴商品的消费人数在2022年全年和2023年前两个月均呈快速增长趋势。用户的购买力和品单价也在提升,实......