P1044 [NOIP2003 普及组] 栈——一种容易理解的方式
转载请注明出处
简述
这是洛谷里的一道题,也是一道非常经典的题,解法有很多,如卡特兰数、动态规划、记忆化搜索,我自己花了一个下午时间把这道题搞明白,方法是很纯粹的动态规划,稍后在代码中便可看出。我会在后面把个人思路尽我所能地表达清楚,若有更好见解也欢迎你的留言与私信,感谢你的阅读。
题目概述
题目在此简述,洛谷中题目链接在此。简单来讲,我们需要求一个1到n的序列经过一次入栈与出栈后,得到的输出序列有多少种。
下面来举一个例子,假如n=3,结果为5,五种结果分别为
1 2 3
1 3 2
2 1 3
2 3 1
3 2 1
个人思路
在我尝试了几种想法之后,我觉得画图能够较为容易把我的思路表达出来,也稍微费了点时间。
首先给出这么一个定义
- 函数R(eleNum, outNum)表示当栈中元素个数为eleNum、外部元素个数为outNum时,最后输出序列的种数。
拿上面n=3的例子来说,开始时eleNum=0、outNum=3,因为确实此时栈中还没有一个元素,外部元素有3个,所以它可以表示成R(0, 3);然后我们把1入栈(注意:此时我们并未说1是否要出栈,那是后面要考虑的事情,意思是在后面它可以选择在何时入或者出),此时它可以表示成R(1, 2),意思大致如此。
现在我们来画几棵树
- 当n=1时,显然R(0,1)=1,这里要说明的是,因为此时栈中为空,我们可以将一个元素入栈,所以R(0,1)=R(1,0)
- 当n=2时,我们先将一个元素入栈,然后考虑第二层(左侧为元素出栈,右侧为不出栈)
- 在左侧,栈再次为空,尝试再将一个元素入栈,我们发现它是R(1,0)=1
- 在右侧,1未出栈,我们接下来将2入栈,结果在此时很容易看出R(2,0)=1
- 求和R(0,2)=R(1,0)+R(2,0)=2
- 当n=3时,分析起来依然不难,1入栈后,考虑第二层
- 在左侧,栈为空,我们将2入栈,此时栈内元素数eleNum为1,外部元素数outNum为1(只有3),结果也就是R(1,1),很幸运的,我们发现R(1,1)我们在n=2时,已经求过,它是2
- 在右侧,我们将2接着入栈,现在还需要考虑第三层
- 左侧,当将2出栈后,因为栈不为空,我们不能将新元素入栈(栈内元素1需要考虑在后面何时出栈),所以R(1,1)!=R(2,0),事实上,只有eleNum为0,R(0,n)=R(1,n-1)才成立(你可以仔细想一下,考虑是否如此)。依然是很幸运,我们再次遇到R(1,1)
- 右侧,当3入栈后,它变成了R(3,0),我们可以不假思索的给出答案R(3,0)=1。现在,你应该能看出一点是R(n,0)=1
- 当n=4时,我想你应该愿意自己尝试一下(最右侧的树),结果在树的上方已经给出。
公式
如果你了解过动态规划的话,给出公式并不难(如果你明白上面的部分,你应该是可以给出公式的),它们像下面这样