入栈出栈序列问题

题目如下:

用n个1和m个0组成字符串,要求任意的前k个字符中,1的个数不能少于0的个数。

问满足要求的字符串数目。

 

 

解法:

该题的解法也是看了一些牛人的提示才知道的,也才知道catalan数这种东东,catalan数的一个典型应用实例跟这个题很相似,其分析过程也很有启发作用,这个应用实例是这样的:

一个栈(无穷大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?

实例分析过程:

对于每一个数来说,必须进栈一次、出栈一次。我们把进栈设为状态‘1’,出栈设为状态‘0’。n个数的所有状态对应n1n0组成的2n位二进制数。由于等待入栈的操作数按照1n的顺序排列、入栈的操作次数b大于等于出栈的操作次数a(ab),因此输出序列的总数目=由左而右扫描由n1n0组成的2n位二进制数,1的累计数不小于0的累计数的方案种数。

2n位二进制数中填入n1的方案数为c(2n,n),不填1的其余n位自动填0。从中减去不符合要求(由左而右扫描,0的累计数大于1的累计数)的方案数即为所求。

不符合要求的数的特征是由左而右扫描时,必然在某一奇数位2m+1位上首先出现m+10的累计数和m1的累计数,此后的2(n-m)-1位上有n-m 1n-m-10。如若把后面这2(n-m)-1位上的01互换,使之成为n-m0n-m-11,结果得1个由n+10n-11组成的2n位数,即一个不合要求的数对应于一个由n+10n-11组成的排列。

反过来,任何一个由n+10n-11组成的2n位二进制数,由于0的个数多2个,2n为偶数,故必在某一个奇数位上出现0的累计数超过1的累计数。同样在后面部分01互换,使之成为由n0n1组成的2n位数,即n+10n-11组成的2n位数必对应一个不符合要求的数。

因而不合要求的2n位数与n10n11组成的排列一一对应。

显然,不符合要求的方案数为c(2n,n+1)。由此得出 输出序列的总数目=c(2n,n)-c(2n,n+1)=1/(n+1)*c(2n,n)

 

上面实例分析中的关键一点就在于要找到一个不符合方案个数的表达式(即实例中的c(2n,n+1)),而要得出此表达式则需要找到一个与不符合方案等价的0,1排列方式(即实例中把n1n0中不符合方案转换为n+10n-11的排列),这里这两者之所以能够等价,是因为n+10n-11的所有排列都会是首先在某个基数位上出现0的累计数超过1的累计数的情况,且把后面的0,1互换之后刚好能够回归n1n0的原始情况,所以与不符合方案一一对应。

 

对本题而言,思路完全一致,我们同样构造一个与不符合方案等价的排列,设现在有n’1m’0,且(m’> n’ & n’+m’=n+m),那么对这n’1m’0的所有排列也都必然是首先在某个奇数位2i+1上出现0的累计数大于1的累计数,及从12i+1位上有i+10i1,后面则还有m’-i-10n’-i1,同样,我们把后面的0,1对换则变成了m’-i-11n’-i0,因此总共变成了m’-i-1+i = m’-11,和n’-i+i+1= n’+10。而要使此排列与源排列中的不符合方案排列等价的话,则必须有m’-1=nn’+1=m,进而得出m’=n+1n’=m-1。即n1m0n>=m)的排列中不符合方案的排列与m-1n+10的所有排列一一对应,所以本题的答案就是C(n+m, n) – C(m+n, n+1)。因为C(n+m, n)= C(n+m, m)C(m+n, n+1) = C(m+n, m-1),所以答案也可以是C(n+m, m)- C(m+n, m-1)等。




应用1描述:n对括号有多少种匹配方式?

       思路:n对括号相当于有2n个符号,n个左括号、n个右括号,可以设问题的解为f(2n)。第0个符号肯定为左括号,与之匹配的右括号必须为第2i+1字符。因为如果是第2i个字符,那么第0个字符与第2i个字符间包含奇数个字符,而奇数个字符是无法构成匹配的。

       通过简单分析,f(2n)可以转化如下的递推式 f(2n) = f(0)*f(2n-2) + f(2)*f(2n - 4) + ... + f(2n - 4)*f(2) + f(2n-2)*f(0)。简单解释一下,f(0) * f(2n-2)表示第0个字符与第1个字符匹配,同时剩余字符分成两个部分,一部分为0个字符,另一部分为2n-2个字符,然后对这两部分求解。f(2)*f(2n-4)表示第0个字符与第3个字符匹配,同时剩余字符分成两个部分,一部分为2个字符,另一部分为2n-4个字符。依次类推。

       假设f(0) = 1,计算一下开始几项,f(2) = 1, f(4) = 2, f(6) = 5。结合递归式,不难发现f(2n) 等于h(n)

       应用2描述:矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?

       思路:可以这样考虑,首先通过括号化,将P分成两个部分,然后分别对两个部分进行括号化。比如分成(a1)×(a2×a3.....×an),然后再对(a1)和(a2×a3.....×an)分别括号化;又如分成(a1×a2)×(a3.....×an),然后再对(a1×a2)和(a3.....×an)括号化。

       设n个矩阵的括号化方案的种数为f(n),那么问题的解为

        f(n) = f(1)*f(n-1) + f(2)*f(n-2) + f(3)*f(n-3) + f(n-1)*f(1)。f(1)*f(n-1)表示分成(a1)×(a2×a3.....×an)两部分,然后分别括号化。

       计算开始几项,f(1) = 1, f(2) = 1, f(3) = 2, f(4) = 5。结合递归式,不难发现f(n)等于h(n-1)

      应用3描述:一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列?

      思路:这个与加括号的很相似,进栈操作相当于是左括号,而出栈操作相当于右括号。n个数的进栈次序和出栈次序构成了一个含2n个数字的序列。第0个数字肯定是进栈的数,这个数相应的出栈的数一定是第2i+1个数。因为如果是2i,那么中间包含了奇数个数,这奇数个肯定无法构成进栈出栈序列。

       设问题的解为f(2n), 那么f(2n) = f(0)*f(2n-2) + f(2)*f(2n-4) + f(2n-2)*f(0)。f(0) * f(2n-2)表示第0个数字进栈后立即出栈,此时这个数字的进栈与出栈间包含的数字个数为0,剩余为2n-2个数。f(2)*f(2n-4)表示第0个数字进栈与出栈间包含了2个数字,相当于1 2 2 1,剩余为2n-4个数字。依次类推。

       假设f(0) = 1,计算一下开始几项,f(2) = 1, f(4) = 2, f(6) = 5。结合递归式,不难发现f(2n) 等于h(n)

       应用4描述:n个节点构成的二叉树,共有多少种情形?

       思路:可以这样考虑,根肯定会占用一个结点,那么剩余的n-1个结点可以有如下的分配方式,T(0, n-1),T(1, n-2),...T(n-1, 0),设T(i, j)表示根的左子树含i个结点,右子树含j个结点。

       设问题的解为f(n),那么f(n) = f(0)*f(n-1) + f(1)*f(n-2) + .......+ f(n-2)*f(1) + f(n-1)*f(0)。假设f(0) = 1,那么f(1) = 1, f(2) = 2, f(3) = 5。结合递推式,不难发现f(n)等于h(n)

       应用5描述:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?

       思路:以其中一个点为基点,编号为0,然后按顺时针方向将其他点依次编号。那么与编号为0相连点的编号一定是奇数,否则,这两个编号间含有奇数个点,势必会有个点被孤立,即在一条线段的两侧分别有一个孤立点,从而导致两线段相交。设选中的基点为A,与它连接的点为B,那么A和B将所有点分成两个部分,一部分位于A、B的左边,另一部分位于A、B的右边。然后分别对这两部分求解即可。

       设问题的解f(n),那么f(n) = f(0)*f(n-2) + f(2)*f(n-4) + f(4)*f(n-6) + ......f(n-4)*f(2) + f(n-2)*f(0)。f(0)*f(n-2)表示编号0的点与编号1的点相连,此时位于它们右边的点的个数为0,而位于它们左边的点为2n-2。依次类推。

       f(0) = 1, f(2) = 1, f(4) = 2。结合递归式,不难发现f(2n) 等于h(n)

      应用6描述:求一个凸多边形区域划分成三角形区域的方法数?

      思路:以凸多边形的一边为基,设这条边的2个顶点为A和B。从剩余顶点中选1个,可以将凸多边形分成三个部分,中间是一个三角形,左右两边分别是两个凸多边形,然后求解左右两个凸多边形。

      设问题的解f(n),其中n表示顶点数,那么f(n) = f(2)*f(n-1) + f(3)*f(n-2) + ......f(n-2)*f(3) + f(n-1)*f(2)。f(2)*f(n-1)表示三个相邻的顶点构成一个三角形,那么另外两个部分的顶点数分别为2和n-1。

      设f(2) = 1,那么f(3) = 1, f(4) = 2, f(5) = 5。结合递推式,不难发现f(n) 等于h(n-2)

      应用7描述:有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?

     思路:可以将持5元买票视为进栈,那么持10元买票视为5元的出栈。这个问题就转化成了栈的出栈次序数。由应用三的分析直接得到结果,f(2n) 等于h(n)

      本人享有博客文章的版权,转载请标明出处 http://blog.csdn.net/wuzhekai1985


你可能感兴趣的:(入栈出栈序列问题)