卡特兰数 (Catalan)

文章介绍了计算卡特兰数的几种公式,包括时间复杂度为O(n^2)的递推式,时间复杂度为O(n)的两种公式,并展示了如何利用这些公式解决编程问题,如球迷购票问题和火车进出栈问题。文中给出了动态规划求解的高效AC代码示例。
摘要由CSDN通过智能技术生成

1.卡特兰数计算公式:

公式一:时间复杂度 O( n^2 )

递推式:h(0) = h(1) = 1                        (n >= 2)

               h(n) = h(0) * h (n -1) + h(1) * h(n - 2) +.....+ h(n - 1) * h(0)         

公式二:时间复杂度 O( n )

             (大数据时h(n)很大,取模时难保证不出现 h(n) % mod = 0)

               h(n) = h(n - 1) * (4 * n - 2) / (n + 1)  

公式三:时间复杂度 O( n )

组合数公式一:     h(n) = C(2n, n) / (n + 1)                (n = 0 , 1, 2.....)        //无法取模

公式四:时间复杂度 O( n )

组合数公式二:      h(n) = C(2n, n) - C(2n, n - 1)             (n = 0, 1, 2.....)        // 可以取模

公式四可以变成公式三:

 2.例题

1.球迷购票问题(球迷购票问题 - 洛谷)

题目背景

盛况空前的足球赛即将举行。球赛门票售票处排起了球迷购票长龙。

按售票处规定,每位购票者限购一张门票,且每张票售价为50元。在排成长龙的球迷中有N个人手持面值50元的钱币,另有N个人手持面值100元的钱币。假设售票处在开始售票时没有零钱。试问这2N个球迷有多少种排队方式可使售票处不致出现找不出钱的尴尬局面。

题目描述

例如当n=2是,用A表示手持50元面值的球迷,用B表示手持100元钱的球迷。则最多可以得到以下两组不同的排队方式,使售票员不至于找不出钱。

第一种:A A B B

第二种:A B A B

[编程任务]

对于给定的n (0≤n≤20),计算2N个球迷有多少种排队方式,可以使售票处不至于找不出钱。

输入格式

一个整数,代表N的值

输出格式

一个整数,表示方案数

输入输出样例

输入 

2

输出 

2

说明/提示

必开QWORD

测试:N=15

回溯:1秒(超时)

模拟栈:大于10分钟

递归算法:1秒(超时)

动态规划:0 MS

组合算法:16 MS

AC代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 30;
typedef unsigned long long ull;
ull f[N];

int main()
{
	int n;
	cin >> n;
	f[0] = f[1] = 1;
	for(int i = 2; i <= n; i++ )
	f[i] = f[i-1] * (4 * i - 2) / (i + 1);		//公式二
	cout << f[n] << endl;
	return 0;
}

2.栈([NOIP2003 普及组] 栈 - 洛谷

AC代码:

//法1 
#include <iostream>
#include <algorithm>

using namespace std;

long long f[40];

int main()
{
	int n;
	cin >> n;
	f[0] = f[1] = 1;
	for(int i = 2; i <= n; i++ )
		f[i] = f[i - 1] * (4 * i - 2) / (i + 1);		//公式二 
	cout << f[n] << endl;
	return 0;
}
#if 0 
//法2 
#include <iostream>
#include <algorithm>

using namespace std;

long long f[40];

int main()
{
	int n;
	cin >> n;
	f[0] = f[1] = 1;
	for(int i = 2; i <= n; i++ )
	{
		for(int j = 0; j < i; j++ )
			f[i] += f[j] * f[i - j - 1];		//递推式 
	}
	cout << f[n] << endl;
	return 0;
}
#endif 

3.火车进出栈问题(130. 火车进出栈问题 - AcWing题库

一列火车 n 节车厢,依次编号为 1,2,3,…,n。

每节车厢有两种运动方式,进栈与出栈,问 n节车厢出栈的可能排列方式有多少种。

输入格式

输入一个整数 n,代表火车的车厢数。

输出格式

输出一个整数 s 表示 n 节车厢出栈的可能排列方式数量。

数据范围

1 ≤ n ≤ 60000

输入样例:
3
输出样例:
5

题解:由于n最大值为6 * 1e4,数据范围过大,使用python解决.

AC代码:

import math                #调用阶乘函数math.factorial()

a = int(input())            #输入转换为整型

print(math.factorial(2 * a) // math.factorial(a) // math.factorial(a) // (a+1))    #公式三

4.火车进栈(129. 火车进栈 - AcWing题库

这里有 n 列火车将要进站再出站,但是,每列火车只有 1 节,那就是车头。

这 n列火车按 1 到 n 的顺序从东方左转进站,这个车站是南北方向的,它虽然无限长,只可惜是一个死胡同,而且站台只有一条股道,火车只能倒着从西方出去,而且每列火车必须进站,先进后出。

也就是说这个火车站其实就相当于一个栈,每次可以让右侧头火车进栈,或者让栈顶火车出站。

车站示意如图:

            出站<——    <——进站
                     |车|
                     |站|
                     |__|

现在请你按《字典序》输出前 20 种可能的出栈方案。

输入格式

输入一个整数 n,代表火车数量。

输出格式

按照《字典序》输出前 20 种答案,每行一种,不要空格。

数据范围

1≤n≤20

输入样例:
3
输出样例:
123
132
213
231
321

AC代码:

#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
 
using namespace std;

vector<int> v;			//出栈序列 
stack<int> s;			//栈 
int ans = 20, sum = 1;		//ans方案数
int n;

void dfs()
{
	if (!ans)		//20种方案 
	return ;
	if (v.size() == n)
	{
		ans--;
		for( auto x : v)			//输出v中元素 
		cout << x;
		cout << endl;
		return ;
	}
	
	if (!s.empty())					//出栈 
	{
		v.push_back(s.top());
		s.pop();
		dfs();
		s.push(v.back());			//状态还原 
		v.pop_back();
	}
	
	if(sum <= n)				//进栈 
	{
		s.push(sum);
		sum ++;
		dfs();
		sum --;			//状态还原 
		s.pop();
	}
}

int main() 
{
	cin >> n;
	dfs();
	return 0; 
}
  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值