洛谷P1044 栈
发布的第10篇博文,纪念一下
题意:
宁宁考虑的是这样一个问题:一个操作数序列,\(1,2,…,n\),栈 \(A\) 的深度大于 \(n\)。
现在可以进行两种操作:
将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的 push 操作)
将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的 pop 操作)
你的程序将对给定的 \(n\),计算并输出由操作数序列 \(1,2,…,n\) 经过操作可能得到的输出序列的总数。
\(n≤18\)
思路:
这题的状态比较难设:
令\(f[i][j]\)表示输出序列有i个数,栈内累计进入了j个数的方案数
不难看出,输出序列没有数,栈内累计不论有多少个数,都仅有一种情况,所以有以下代码(预处理):
for(int i=0;i<=n;i++)
{
f[0][i]=1;
}
每一次,我们都有两种操作:
1、向栈内弹进一个数,即为\(f[i][j-1]\)
2、从栈内弹出一个数。即为\(f[i-1][j+1]\)
但是,要注意当栈为空时(\(i=j\)),仅能向内弹进一个(因为没有东西可以弹出了)。
因此,转移方程便为
\(i=j\)时
\(f[i][j]=f[i][j-1]\)
\(i≠j\)时
\(f[i][j]=f[i][j-1]+f[i-1][j+1]\)
code:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N=20;
int n,f[N][N];
int main()
{
cin>>n;
for(int i=0;i<=n;i++)
{
f[0][i]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(j==i)
f[i][j]=f[i][j-1];
else
f[i][j]=f[i-1][j+1]+f[i][j-1];
}
}
cout<<f[n][n];
return 0;
}