题意
给定一个 n ( 1 ≤ n ≤ 18 ) n(1 \leq n \leq 18) n(1≤n≤18),表示一个操作数序列, 1 , 2 , … , n 1,2,…,n 1,2,…,n(图示为 1 到 3 的情况),栈 A 的深度大于 n n n。
现在可以进行两种操作,
- 将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的 push 操作)
- 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的 pop 操作)
下图为当
n
=
3
n = 3
n=3 时一种合法的解(即 2 3 1
)
你的程序将对给定的 n n n,计算并输出由操作数序列 1 , 2 , … , n 1,2,…,n 1,2,…,n 经过操作可能得到的输出序列的总数。
思路
考虑 d p i , j dp_{i,j} dpi,j 表示当前已经用了 i i i 次进栈操作和 j ( 1 ≤ j ≤ i ) j(1\leq j \leq i) j(1≤j≤i) 次操作的方案数,则当前方案可能由两种方案推来:
- 当前进行的是进栈操作,则 d p i , j ← d p i − 1 , j dp_{i,j} \gets dp_{i - 1,j} dpi,j←dpi−1,j,无须担心 i = j i = j i=j时会不会有问题,因为当 i = j i=j i=j 时 i − 1 < j i - 1< j i−1<j,因此 d p i − 1 , j dp_{i - 1,j} dpi−1,j 等于初始值,即为 0 0 0。
- 进行的是出栈操作,则 d p i , j ← d p i , j − 1 dp_{i,j} \gets dp_{i,j - 1} dpi,j←dpi,j−1。
综上所述, d p i , j ← d p i − 1 , j + d p i , j − 1 , 1 ≤ j ≤ i dp_{i,j} \gets dp_{i - 1,j} + dp_{i,j - 1},1 \leq j \leq i dpi,j←dpi−1,j+dpi,j−1,1≤j≤i
考虑边界条件,对于进栈次数为 i i i 并且从未出栈,则方案数肯定为 1 1 1, d p i , 0 = 1 dp_{i,0} = 1 dpi,0=1。
答案显而易见为 d p n , n dp_{n,n} dpn,n。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,dp[20][20];
signed main() {
scanf("%lld",&n);
for(int i = 1;i <= n;i++) dp[i][0] = 1;
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= i;j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
printf("%lld\n",dp[n][n]);
return 0;
}