一、引入
初学数据结构与算法,学到栈的时候,总是会遇到这样一类问题,
设输入序列为1,2,3,则经过栈的作用后可以得到()中不同的输出序列。
接着就开始一直在想,谁入栈,谁出栈,数字少还好,但数字一多起来,我就开始出现遗漏和重复,所以我只想有没有一种方法,或是说一种公式,可以让我在计算诸如此类问题时,可以最大的保证正确率,我抱着这样的目的,作此题解,以保证自己可以反复复习。
二、朴素算法
栈作为一种先进后出的特殊线性表,我们只能在他的一段进行操作。但由于允许出栈入栈穿插进行,我们可以选择将输入元素压入栈中,也可以在任意时刻把栈顶元素弹出。对于一个给定的输入序列,在栈的作用下,会产生不同的输出队列。
样例演示
如图所示,1, 2, 3的序列一共有五种,想起来老废劲了。接下来让我们找找有没有什么好方法来计算这道题。
三、卡特兰数的介绍
卡特兰数是一种数学上的数列,由法国数学家卡特兰(Catalan)在1838年首次提出。它的计算方式是:C0 = 1,Cn+1 = (2(2n+1)/(n+2))*Cn,其中n>=0。这个数列在组合数学、计算机科学、统计学等领域有广泛的应用。
卡特兰数是一个非常有用的数学工具,能够用于解决许多问题,其中之一就是栈的问题。
在使用栈时,常常需要考虑栈的各种操作的顺序,以确保栈操作的正确性。而卡特兰数正好可以帮助我们计算各种可能的栈操作顺序的数量,从而简化了栈操作的分析和设计。
这里我们可以使用卡特兰数来计算栈的出栈问题:
经过上述推导我们得到计算公式:
f
(
n
)
=
C
2
n
n
n
+
1
f(n) = \frac{C^n_{2n}}{n + 1}
f(n)=n+1C2nn
我们可以验证一下:
f
(
3
)
=
C
6
3
3
+
1
=
5
f(3) = \frac{C^3_6}{3 + 1} = 5
f(3)=3+1C63=5
答案完全正确!!!!!
四、卡特兰数的实现
如果只是为了作对这道题,我们完全可以记住公式,但作为热爱计算机的热血青年来说,我们一定要学会这道题的基本实现。
1.递推实现卡特兰数
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 100;
int n;
int C[N];
void catalan() {
C[0] = C[1] = 1;
for (int i = 2; i <= n; i ++) {
for (int j = 0; j < i; j ++)
C[i] += C[j] * C[i - j - 1];
}
}
int main()
{
cin >> n;
catalan();
cout << C[n] << endl;
return 0;
}
2.组合数法实现卡特兰数
#include<iostream>
#include<algorithm>
#include<cstring>
#include <vector>
using namespace std;
const int N = 5010;
int primes[N], sum[N], cnt;
bool st[N];
void get_primes(int n)
{
for(int i = 2; i <= n; i ++)
{
if(!st[i]) primes[cnt ++] = i;
for(int j = 0; i * primes[j] <= n; j ++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
int get(int n, int p)
{
int res = 0;
while (n)
{
res += n/p;
n = n/p;
}
return res;
}
vector<int> mul(vector<int> &A, int b) // C = A * b, A >= 0, b >= 0
{
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; i ++ )
{
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
int m;
cin >> m;
int a = 2 * m, b = m;
get_primes(a);
for(int i = 0; i < cnt; i ++)
{
int p = primes[i];
sum[i] = get(a, p) - get(a - b, p) - get(b, p);
}
vector<int> res;
res.push_back(1);
for(int i = 0; i < cnt; i ++)
{
for(int j = 0; j < sum[i]; j ++)
{
res = mul(res, primes[i]);
}
}
int c = 0;
for (int i = res.size() - 1; i >= 0; i -- )
{
c = c * 10 + res[i];
}
cout << c/(m + 1) << endl;
return 0;
}
五、结语
这是这一章的全部内容,喜欢的话可以点赞支持一下,我们一起努力!