问题描述:栈是常用的一种数据结构,有n令元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。你已经知道栈的操作有两·种:push和pop,前者是将一个元素进栈,后者是将栈顶元素弹出。现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。请你编程求出对于给定的n,计算并输出由操作数序列1,2,…,n,经过一系列操作可能得到的输出序列总数。
输入:
一个整数n
输出:
一个整数,即可能输出序列的总数目
样例输入:
3
样例输出:
5
问题分析:
由题目可知,可能的动作只有进栈和出栈,且出栈次数<=入栈次数,因此可修改该问题的表现。假设N=3,建立一个(N+1)×(N+1)的网格,如下图所示(以线段交叉点为网格点):
从网格左下角出发,规定向上走一步为一次入栈操作,向右走一步为一次出栈操作,由于出栈次数<=入栈次数,因此可行范围限定在对角线及其以上区域。设N(m,n)是经过n次入栈,m次出栈后可能的结果数量,由图可知,入栈n次,出栈m次,是由一次出栈或一次出栈形成的。因此N(m,n)=N(m-1,n)+ N(m,n-1),其中N(0,0)=1,即初始状态为1;左侧边界表示只能有入栈操作,因此N(0,n)=N(0,n-1)。图中×表示不可能出现的情况,因此也可以认为是0。这样N(3,3)便为元素为3的情况下所有可能的出栈序列的次数。
源代码(C语言描述,数据输入输出均以文件形式给出,输入文件为input.in,输出文件为output.out)
#include <stdio.h>
#include <stdlib.h>
int D[13][13];//默认栈最大为13,如有需要请自行修改
void Stack(int M)
{
int i,j;
for (i=0;i<=M;i++)
{
for (j=0;j<=M;j++)
{
D[i][j]=0;
}
}
for (i=0;i<=M;i++)
{
D[i][0]=1;
}
for (i=1;i<=M;i++)
{
for (j=1;j<=M;j++)
{
if (i>=j)
{
D[i][j]=D[i-1][j]+D[i][j-1];
}
}
}
}
void main()
{
int M;
FILE * fp;
fp = fopen("input.in","r");
fscanf(fp,"%d",&M);
Stack(M);
fp = fopen("output.out","w");
fprintf(fp,"%d", D[M][M]);
fclose(fp);
}
附件:测试数据。来源:信息学奥林匹克(中学高级本)。组织方式:输入文件stackX.in,对应输出文件stackX.out,共10组。
下载地址: http://pan.baidu.com/share/link?shareid=1617967651&uk=503766013