程式設計之美 買票找零 卡特蘭數

2021-07-15 22:26:50 字數 4175 閱讀 2219

第一次看這題的時候沒有好好注意,後來發現這是一類大問題,學習了卡特蘭數這個概念,順便又複習了高中的排列組合知識、、、

先看一下書中引入卡特蘭數的例子:

《程式設計之美》4.3買票找零:2n個人排隊買票,其中n個人持50元,n個人持100元。每張票50元,且一人只買一張票。初始時售票處沒有零錢找零。請問這2n個人一共有多少種排隊順序,不至於使售票處找不開錢?

分析1:隊伍的序號標為0,1,…,2n-1,並把50元看作左括號,100元看作右括號,合法序列即括號能完成配對的序列。對於乙個合法的序列,第0個一定是左括號,它必然與某個右括號配對,記其位置為k。那麼從1到k-1、k+1到2n-1也分別是兩個合法序列。那麼,k必然是奇數(1到k-1一共有偶數個),設k=2i+1。那麼剩餘括號的合法序列數為f(2i)*f(2n-2i-2)個。取i=0到n-1累加即:

f(2n)=f(0)*f(2n-2)+f(2)*f(2n-4)+······+f(2n-4)*f(2)+f(2n-2)*f(0)

並且令f(0)=1,再由組合數c(0,0)=0,可得

以上就是一種卡特蘭數的通項公式,下面具體介紹一下卡特蘭數。

我接觸到的公式的定義有兩種形式,一種是上面的f(2n),

f(2n)=f(0)*f(2n-2)+f(2)*f(2n-4)+······+f(2n-4)*f(2)+f(2n-2)*f(0)

還有一種就是下面的f(n)的

令f(0)=1,f(1)=1,catalan數滿足遞推式[1] :

f(n)= f(0)*f(n-1)+f(1)*f(n-2) + … + f(n-1)*f(0) (n>=2)

其實這兩種只是表現形式不同,因為具體問題中,關鍵元素都是成對出現的,比如n對括號,總的個數就是2n個,所以一定要理解這兩個個公式並結合具體問題具體分析。

卡特蘭數的遞推關係為

也就是f(2n)=c(2n, n)/(n+1)

下面是證明過程

在《計算機程式設計藝術》,第三版,donald e.knuth著,蘇運霖譯,第一卷,508頁,給出了證明:

問題大意是用s表示入棧,x表示出棧,那麼合法的序列有多少個(s的個數為n)

顯然有c(2n, n)個含s,x各n個的序列,剩下的是計算不允許的序列數(它包含正確個數的s和x,但是違背其它條件).

在任何不允許的序列中,定出使得x的個數超過s的個數的第乙個x的位置.然後在導致幷包括這個x的部分序列中,以

s代替所有的x並以x代表所有的s.結果是乙個有(n+1)個s和(n-1)個x的序列.反過來,對一垢一種型別的每個序列,我們都能

逆轉這個過程,而且找出導致它的前一種型別的不允許序列.例如xxsxsssxxsss必然來自ssxs***xxsss.這個對應說明,不允許

的序列的個數是c(2n, n-1),因此

an = c(2n, n) - c(2n, n-1).[comptes rendus acad.sci.105(paris, 1887), 436~437]

對於乙個無限大的棧,一共n個元素,請問有幾種合法的入棧出棧形式?

分析:n個元素出棧入棧操作共有2n個,且任何前x個操作中入棧操作必須不少於出棧操作,直接用f(2n)計算即可

p = a1 * a2 * a3 * … * an,其中ai是矩陣。根據乘法結合律,不改變矩陣的相互順序,只用括號表示成對的乘積,試問一共有幾種括號化方案?

分析:n個矩陣相乘需要n-1對括號,且任何前x個元素中」(」的個數一定大於」)」的個數,所以應該為f(2(n-1))

某個城市的某個居民,每天他須要走過2n個街區去上班(他在其住所以北n個街區和以東n個街區處工作)。如果他不跨越(但可以碰到)從家到辦公室的對角線,那麼有多少條可能的道路?

分析:其實也與括號問題相似,這個人一共要走2n步,其中向右與向上分別n步,那麼,假設他第一步是向右的,那麼之後的任何時刻,他向右的步數都不能少於想上的步數,即f(2n),當然,他也可以第一步時先向上,同樣有f(2n)種走法,兩者應該是以對角線對稱的,所以答案為2*f(2n)。

在圓上選擇2n個點,將這些點成對連線起來,且所得n條線段不相交,求可行的方法數。

分析:乍一看不能像上面三道題那樣直接套公式。那麼,先進行一下分析,將圓上的點依次標為p0,p1,…p2n-1。為了避免混淆,使用f(2n)表示2n個點可連成的線段數,選擇pk與p0相連(0< k< n)同樣地可以看出,k必為奇數,否則1至k-1之間有奇數個點,不可能成對連成直線。同樣地把k設為2i+1,那麼線段p0pk把剩餘的點分為了1…2i和2i+2…2n-1,且新的連線不能與0k相交,它們只能屬於0k把園劃分出的這兩個區域之一。即f(2n) = ∑f(2i)*f(2n-1-(2i+2)+1) = ∑f(2i)*f(2n-2i-2),其中i = 0 … n-1。這時,又轉化成熟悉的形式了。

以上的應用中用到的公式都是f(2n),也可以發現他們有這如下幾個特點:

元素都是成對出現的,比如左右括號,出棧與入棧,向右走與向上走,而且都是n對,所以f(2n),即表示n對2n個。

都需要滿足乙個特點,即任意前x個元素中,某個元素的個數不小於與之對應的元素個數,比如左括號不少於右括號,入棧不少於出棧等。

通常滿足以上兩個特點,就可以使用f(2n)這個公式,但是並不是所有問題都是類似的,下面就介紹幾個使用f(n)的例子。

n個結點可構造多少個不同的二叉樹。(結點之間沒有區別)

分析:這次並沒有成對出現的元素了,n可以為奇數也可以為偶數,可以這樣考慮:n個節點中肯定有乙個根節點,剩下的n-1個節點可以這樣分配t(0, n-1),t(1, n-2),…t(n-1, 0),其中t(i, j)中i,j表示左右子樹的個數。

於是可以寫出公式:f(n) = f(0)*f(n-1) + f(1)*f(n-2) + …….+ f(n-2)*f(1) + f(n-1)*f(0)

將多邊形劃分為三角形問題。求乙個凸多邊形區域劃分成三角形區域的方法數。

分析:以凸多邊形的一邊為基,設這條邊的2個頂點為a和b。從剩餘頂點中選1個,可以將凸多邊形分成三個部分,中間是乙個三角形,左右兩邊分別是兩個凸多邊形,然後求解左右兩個凸多邊形。

設n邊形的解為h(n),那麼h(n) = h(2)*h(n-1) + h(3)*h(n-2) + ……h(n-2)*h(3) + h(n-1)*h(2)。h(2)*h(n-1)表示三個相鄰的頂點構成乙個三角形,那麼另外兩個部分的頂點數分別為2和n-1。

設h(2) = 1,那麼h(3) = 1, h(4) = 2, h(5) = 5。結合遞推式,不難發現h(n) 等於f(n-2)。就是上面介紹的公式。

可以看出,這兩道題和上面的稍微有些區別,用的公式是f(n)

這裡的n可以為奇數也可以為偶數

元素並不是成對出現,也沒有上面說的某個元素個數必須不少於與之對應的元素個數

他的特點在於把乙個大問題劃分為兩個性質相同的規模更小的問題,然後一直遞迴下去,直到f(0)=1

還在網上找到一道筆試題

在乙個2*n的格仔中填入1到2n這些數值使得每個格仔內的數值都比其右邊和下邊的所有數值都小的情況數;

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

分析:這2n個數選擇n個在第一行,剩下的n個在第二行,並且每行都是從小到大排列。比如00001111就對應了1、2、3、4在第一行,5、6、7、8在第二行。為了使第一行比第二行對應位置小,換句話說,要保證序列合法,那麼任何從第乙個元素的開始的任意子序列中0的個數要大於等於1的個數。這就轉化成了f(2n)。

學習了卡特蘭數,了解了這類問題的基本思路。

這類問題的應用大致分為上面介紹的兩類,需要根據具體問題來分析使用f(2n)還是f(n)這兩個公式,但其實這兩個公式本質上是乙個。

有寫問題隱藏的比較深,比如兩排人照相問題,要善於從具體的問題抽象為具體的數學模型。

2、catalan數(卡特蘭數)

程式設計之美 買票找零

一,問題 n個拿著1元,n個人拿著2元去買票。票價一元,且售票元只能用n個人購票的一元給2元的找零。問有幾種排列方法 分析 卡特蘭數方法 遞推公式 f 2 n f 0 f 2 n 1 f 1 f 2 n 2 f 2 n 1 f 0 f n f 0 f n 1 f 1 f n 2 f n 1 f 0 ...

程式設計之美1 15 構造數獨

問題 構造乙個9 9的方格矩陣,玩家要在每個方格中,分別填上1至9的任意乙個數字,讓整個棋盤每一列 每一行以及每乙個3 3的小矩陣中的數字都不重複。首先我們通過乙個深度優先搜尋來生成乙個可行解,然後隨機刪除一定數量的數字,以生成乙個數獨。include include using namespace...

程式設計之美 1 15 構造數獨

1.15 構造數獨 數獨的棋盤,由9 9 81個小方格組成,數獨要求每一行 每一列 以及每乙個3 3的小矩陣中的數字都不重複 深度優先搜尋,回溯法 從 0,0 開始,沒有處理的呼叫函式獲取可能的取值,取乙個為當前值,搜尋下乙個個子,搜尋過程中,若出現某個格仔沒有可行值,則回溯,修改前乙個格仔的取值 ...