1. 程式人生 > >動態規劃之n個元素出棧順序種數

動態規劃之n個元素出棧順序種數

  1. 問題描述
    n個元素依次進棧,共有多少種出棧順序?
  2. 演算法分析
    1個元素進棧,有1種出棧順序;2個元素進棧,有2種出棧順序;3個元素進棧,有5種出棧順序
    我們把n個元素的出棧個數的記為f(n), 那麼對於1,2,3, 我們很容易得出:

                                 f(1) = 1     //即 1
                                 f(2) = 2     //即 12、21
                                 f(3) = 5     //即 123、132、213、321、231
    

    然後我們來考慮f(4), 我們給4個元素編號為a,b,c,d, 那麼考慮:元素a只可能出現在1號位置,2號位置,3號位置和4號位置(很容易理解,一共就4個位置,比如abcd,元素a就在1號位置)。
    分析:

    1) 如果元素a在1號位置,那麼只可能a進棧,馬上出棧,此時還剩元素b、c、d等待操作,就是子問題f(3);
    2) 如果元素a在2號位置,那麼一定有一個元素比a先出棧,即有f(1)種可能順序(只能是b),還剩c、d,即f(2), 根據乘法原理,一共的順序個數為f(1) * f(2);
    3) 如果元素a在3號位置,那麼一定有兩個元素比1先出棧,即有f(2)種可能順序(只能是b、c),還剩d,即f(1),
    根據乘法原理,一共的順序個數為f(2) * f(1);
    4) 如果元素a在4號位置,那麼一定是a先進棧,最後出棧,那麼元素b、c、d的出棧順序即是此小問題的解,即 f(3);
    結合所有情況,即f(4) = f(3) + f(2) * f(1) + f(1) * f(2) + f(3);
    為了規整化,我們定義f(0) = 1;於是f(4)可以重新寫為:
    f(4) = f(0)f(3) + f(1)*f(2) + f(2)

    f(1) + f(3)*f(0)
    然後我們推廣到n,推廣思路和n=4時完全一樣,於是我們可以得到:
    f(n) = f(0)*f(n-1) + f(1)*f(n-2) + … + f(n-1)*f(0)

    這裡寫圖片描述
    具體可以搜尋Catalan數

  3. 程式程式碼

#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    int n;
    cin >> n;
    int* arr = new int[n+1];
    memset(arr, 0, sizeof
(int)*(n+1)); arr[0] = 1; arr[1] = 1; //遞推關係式 for (int i=2; i<=n; ++i) { for (int j=0; j<i; ++j) { arr[i] += arr[j] * arr[i-1-j]; } } cout << arr[n] << endl; delete[] arr; return 0; }