出栈序列统计

问题描述:栈是常用的一种数据结构,有n令元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。你已经知道栈的操作有两·种:pushpop,前者是将一个元素进栈,后者是将栈顶元素弹出。现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。请你编程求出对于给定的n,计算并输出由操作数序列12n,经过一系列操作可能得到的输出序列总数。

输入:

       一个整数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的情况下所有可能的出栈序列的次数。

      该问题求解需要一个(N+1)×(N+1)的网格进行辅助运算,所以空间复杂度为O(n 2),由于是从前往后的递推求解,因此可用两层循环嵌套的方式计算出网格内的所有点,因此时间复杂度为O(n 2)。

源代码(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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值