1. 程式人生 > 實用技巧 >進出棧序列問題詳解

進出棧序列問題詳解

連結:https://ac.nowcoder.com/acm/contest/1005/B

題目描述

一列火車n節車廂,依次編號為1,2,3,…,n。每節車廂有兩種運動方式,進棧與出棧,問n節車廂出棧的可能排列方式有多少種。

輸入描述:

一個數,n(n≤60000)n (n \leq 60000)n(n≤60000)

輸出描述:

一個數s表示n節車廂出棧的可能排列方式

示例1

輸入

3

輸出

5

示例2

輸入

50

輸出

1978261657756160653623774456

思路:

方案一:暴力列舉

對於棧問題,簡單來想只有進棧和出棧的操作

所以直觀的來看,直接暴力列舉每個節點情況

\(\begin{cases}1.把下一個數進棧\\2.把當前棧頂元素出棧(如果棧非空)\end{cases}\)

利用遞迴快速實現,時間複雜度 :\(O(2^N)\)

在這個時間複雜度下很容易TLE

方案二:遞推優化 \(O(N^2)\)

因為本題只是要求求出有多少種出棧序列並不關心具體方案,於是我們可以使用遞推直接進行統計。設\(S_N\) 表示進棧順序為 \(1,2,3,4...,N\) 時可能的出棧序列總數。

現在假設序列中位置 \(K\) 的地方有一個數 \(a ,a\)前面有\(K−1\)個數要出棧,a後面有\(N−K\)個數要出棧,而出棧的方案總數分別是 $S_{K−1} $ 和 \(S_{N−K}\) 於是這個大問題就轉化成了小問題,我們就要求更小的 \(S_i\),於是有遞推公式(很好理解):

方案三:動態規劃 \(O(N^2)\)

動態規劃。這裡我們要有狀態與決策的思想(這個真的很重要,有時與搜尋也異曲同工)。我們設 \(F[i,j]\) 是還有 $i \(個元素未入棧,\)j$ 個元素在棧中的方案總數,初始狀態是\(F[0,0]=1\),目標狀態是\(F[N,0]F\),每一次我們的決策有“讓一個數進棧”,“讓棧頂的數出棧”,所以方程有:

\[F[i,j]=F[i−1,j+1]+F[i,j−1] \]

方案四:數學 \(O(N)\)

該問題等價於求第 \(N\)\(Ctalan\)數,即 \(C^{N}_{2N} / (N + 1)\)