一道面試題到卡特蘭數及其應用
繪畫展覽門票每張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;
}
}