1. 程式人生 > >一道面試題到卡特蘭數及其應用

一道面試題到卡特蘭數及其應用

繪畫展覽門票每張5元,如果有2n個人排隊購票,每人一張,並且其中一半人恰有5元錢,另一半人恰有10元錢,而票房無零錢可找,那麼如何將這2n個人排成一列,順次購票,使得不至於因票房無零錢可找而耽誤時間,應該採用什麼演算法解決呢?(分支限界法)

這個是卡特蘭數的經典應用。那麼,我們先來看一下卡特蘭數是什麼東西呢?

Catalan數的定義:

令h(1)=1,Catalan數滿足遞迴式:h(n) = h(1)h(n-1) + h(2) h(n-2) + … +
h(n-1)*h(1),n>=2

該遞推關係的解為:h(n) = c(2n, n)/(n+1) = c(2n, n) - c(2n, n-1)

問題描述:

12個高矮不同的人,排成兩排,每排必須是從矮到高排列,而且第二排比對應的第一排的人高,問排列方式有多少種?

應用公式:c(2n, n)/(n+1)。

而c(12, 6)/7 = 12*11*10*9*8*7/(7*6*5*4*3*2) = 132

注意:c(2n, n)/(n+1) = c(2n, n) - c(2n, n-1)

應用

1、括號化

矩陣連乘: P=a1×a2×a3×……×an,依據乘法結合律,不改變其順序,只用括號表示成對的乘積,試問有幾種括號化的方案?

h(n-1)種

2、出棧次序

一個棧(無窮大)的進棧序列為1,2,3,…,n,有多少個不同的出棧序列?

輸出序列的總數目=c(2n,n)-c(2n,n+1)=c(2n,n)/(n+1)=h(n)。

類似問題:

                         買票找零

有2n個人排成一行進入劇場。入場費5元。其中只有n個人有一張5元鈔票,另外n人只有10元鈔票,劇院無其它鈔票,問有多少中方法使得只要有10元的人買票,售票處就有5元的鈔票找零?(將持5元者到達視作將5元入棧,持10元者到達視作使棧中某5元出棧)

3、凸多邊形三角劃分

在一個凸多邊形中,通過若干條互不相交的對角線,把這個多邊形劃分成了若干個三角形。任務是鍵盤上輸入凸多邊形的邊數n,求不同劃分的方案數f(n)。比如當n=6時,f(6)=14。

f(n)=h(n-2) (n=2,3,4,……)

類似問題:

一位大城市的律師在她住所以北n個街區和以東n個街區處工作。每天她走2n個街區去上班。如果她從不穿越(但可以碰到)從家到辦公室的對角線,那麼有多少條可能的道路?

在圓上選擇2n個點,將這些點成對連線起來使得所得到的n條線段不相交的方法數?

4、給定節點組成二叉搜尋樹

給定N個節點,能構成多少種不同的二叉搜尋樹?

(能構成h(N)個) (這個公式的下標是從h(0)=1開始的)

求卡特蘭數程式碼如下:

void catalan() //求卡特蘭數
{
    int i, j, len, carry, temp;
    a[1][0] = b[1] = 1;
    len = 1;
    for(i = 2; i <= 100; i++)
    {
        for(j = 0; j < len; j++) //乘法
        a[i][j] = a[i-1][j]*(4*(i-1)+2);
        carry = 0;
        for(j = 0; j < len; j++) //處理相乘結果
        {
            temp = a[i][j] + carry;
            a[i][j] = temp % 10;
            carry = temp / 10;
        }
        while(carry) //進位處理
        {
            a[i][len++] = carry % 10;
            carry /= 10;
        }
        carry = 0;
        for(j = len-1; j >= 0; j--) //除法
        {
            temp = carry*10 + a[i][j];
            a[i][j] = temp/(i+1);
            carry = temp%(i+1);
        }
        while(!a[i][len-1]) //高位零處理
        len --;
        b[i] = len;
    }
}