0415-栈
题目描述
关系
内容
栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表。
栈有两种最重要的操作,即
栈的重要性不言自明,任何一门数据结构的课程都会介绍栈。
宁宁同学在复习栈的基本概念时,想到了一个书上没有讲过的问题,而他自己无法给出答案,所以需要你的帮忙。
宁宁考虑的是这样一个问题:一个操作数序列,从
现在可以进行两种操作,
- 将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的
操作)。 - 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的
操作)。
使用这两种操作,由一个操作数序列就可以得到一系列的输出序列。
你的程序将对给定的
输入格式
输入文件只含一个整数
输出格式
输出文件只有一行,即可能输出序列的总数目。
数据范围
输入样例:
3
输出样例:
5
问题分析
思路分析
我们以最后一个出栈的数作为分类讨论的依据,如果最后一个出栈的数为 k,那么比 k 早入栈的数有 k - 1 个,比 k 晚入栈的数有 n - k 个。所以前 k - 1 个数的出栈序列和后面 n - k 的数的出栈序列是子问题,于是我们就可以写出以下递推式:
假设
这就是卡特兰数的递推式,于是我们可以直接使用公式法。
由于 n 很小,所以我们直接用 dp 求出即可。
定义 f[i]:长度为 i 的输出序列的总数。
显然 f[1] = f[0] = 1。
为什么前 k - 1 个数和后 n - k 个数是子序列呢?第 k 个数是最后一个弹出序列,这就意味着 k 入栈后就一定处于栈底,所以,前 k - 1 个数都已经弹出栈了,与 k 无关;后 n - k 个数一定为 k 的上面,所以也与 k 无关。所以,这两堆数一定是独立的。
拓展
0096-unique-binary-search-trees
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 25;
int n;
int f[N];
int main()
{
cin >> n;
f[0] = f[1] = 1;
for (int i = 2; i <= n; i++) // 枚举长度
for (int k = 1; k <= i; k++) // 枚举哪个是最后一个出栈
f[i] += f[k - 1] * f[i - k];
cout << f[n];
}