進出棧序列問題詳解
連結: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)\)