入棧順序一定,出棧的合法序列種類個數

題目

設有一個數列的輸入順序爲123456,若採用棧結構,並以A和D分別表示入棧和出棧操作,試問通過進棧和出棧操作的合法序列有多少種?

解題

三種辦法,結果是132種序列。

1. 列舉法

不是直接一個個去列,而是找技巧。先列數列元素個數爲1的,再是2的,最後一直到6個,可以找到一定的規律得出結果。

2. 代碼

畢竟作爲一名軟件工程的學生,用老師的話說,“你們寫代碼的能力是要求比計算機科學的同學強的,寫代碼對於你們應該像喝水吃飯一樣簡單,這是最基礎的!”。於是我在列舉法之後考慮是否能用代碼解決這個問題。事實證明是可以的,我的想法如下:

入棧、出棧順序(A,D的排列)有兩個要求:

1. 共有12個位置,A、D各六個;

2. 任取前n個(n<=12),A的數量應該大於等於D的數量(入了才能出啊,入的不能少於出的),且n=12時,num(A)=num(D)=6

只用遍歷每一種可能即可。那麼應該如何遍歷?使得容易檢測這兩個條件,且使得時間複雜度較小(12個for循環就算了)

我的想法是利用二進制數遍歷。即遍歷0~2^{12}-1這4096個十進制數,轉化爲二進制數,爲了檢驗第二個條件,我把12進制數中的0變爲-1,1不變,只用檢測前n位加起來是否>=0即可,取出每一位的方法是先除再取餘。具體代碼如下:

// main.cpp
// gcc編譯通過
#include <iostream>
#include <stdio.h>
using namespace std;

// 10的11次方已經超過int範圍
// 十進制轉換爲二進制,用的遞歸
long long transform(int num)
{
    if(!num) return 0;
    return num % 2 + 10 * transform(num / 2);
}

// 計算10的次方,目的是取數字的每一位
// C++自帶的pow以及pow10返回double,不符合要求,只好自己寫
long long pow10(int b)
{
    long long sum = 1;
    for (int i = 0; i < b; i++)
    {
        sum *= 10;
    }
    return sum;
}

int main()
{
    int sum = 0;
    int count = 0;
    long long num2 = 0;
    int tmp = 0;
    bool flag = false;

    // 遍歷可能性
    for (int a = 4095; a >= 1; a -= 1)
    {
        sum = 0;
        flag = true;
        num2 = transform(a);
        for (int b = 11; b >= 0; b--)
        {
				// 取每一位
            tmp = (num2 / pow10(b)) % 10;
            if (tmp == 0) sum += -1;
            else if (tmp == 1) sum += 1;
            
            if (sum < 0)
            {
                flag = false;
                break;
            }
        }

        if (flag && !sum)
        {
            count++;
        }
    }
    
    cout << count <<endl;
    getchar();
    return 0;
}

3. 公式法

我認爲這個題目上面兩種辦法還是需要懂一點腦筋的,於是問其他幾個同學他們是怎麼做的,結果被告知他們都是直接上網查這個題目,發現有公式,就直接拿過來解題了((⊙o⊙)…,機智啊)。

這個棧的出棧序列是卡特蘭數的一個運用。

卡特蘭數-度娘百科

首次出空之前第一個出棧的序數k將1~n的序列分成兩個序列,其中一個是1~k-1,序列個數爲k-1,另外一個是k+1~n,序列個數是n-k。

此時,我們若把k視爲確定一個序數,那麼根據乘法原理,f(n)的問題就等價於——序列個數爲k-1的出棧序列種數乘以序列個數爲n - k的出棧序列種數,即選擇k這個序數的f(n)=f(k-1)×f(n-k)。而k可以選1到n,所以再根據加法原理,將k取不同值的序列種數相加,得到的總序列種數爲:f(n)=f(0)f(n-1)+f(1)f(n-2)+……+f(n-1)f(0)。

卡特蘭數的公式是:

\tfrac{1}{n+1}\cdot C_{2n}^{n}

其中n爲元素個數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章