Catalan數應用整理

應用一:

codevs 3112 二叉樹計數

 時間限制: 1 s
 空間限制: 128000 KB
 題目等級 : 黃金 Gold
 
題目描述  Description

一個有n個結點的二叉樹總共有多少種形態ios

輸入描述  Input Description

讀入一個正整數nflask

輸出描述  Output Description

輸出一個正整數表示答案app

樣例輸入  Sample Input

6ide

樣例輸出  Sample Output

132spa

數據範圍及提示  Data Size & Hint

1<=n<=20code

 1 #define N 25
 2 #include<cstdio>
 3 #include<iostream>
 4 using namespace std;
 5 long long f[N];
 6 int main()
 7 {
 8     int n;
 9     scanf("%d",&n);
10     f[0]=1;f[1]=1;
11     for(int i=2;i<=n;++i)
12       for(int k=0;k<i;++k)
13       f[i]+=f[k]*f[i-1-k];
14     printf("%d\n",f[n]);
15     return 0;
16 }

下面解釋:爲何n個節點的二叉樹的形態數目是Catalan數?blog

 1 /*
 2 先考慮只有一個節點的情形,設此時的形態有f(1)種,那麼很明顯f(1)=1
 3 
 4 若是有兩個節點呢?咱們很天然想到,應該在f(1)的基礎上考慮遞推關係。那麼,若是固定一個節點後,有兩種狀況,一是左子樹還剩一個節點,此刻類型數量爲f(1),第二種狀況是右子樹生一個節點,此刻類型數量爲f(1),固有f(2) = f(1) + f(1)
 5 
 6 若是有三個節點呢?咱們須要考慮固定兩個節點的狀況麼?固然不行,爲何?
 7 
 8 由於當節點數量大於等於2時,不管你如何固定,其形態必然有多種,而在這多種基礎之上你如何安排後續剩下的節點呢?因此必須挑出這個誤區。
 9 
10 回到二叉樹的定義,二叉樹本質上就是一個遞歸的形式,左子樹,右子樹,根節點。因此根節點應該不變,須要遞歸處理的是左右子樹。
11 
12 也就是說,仍是考慮固定一個節點,即根節點。好的,按照這個思路,還剩2個節點,那麼左右子樹的分佈狀況爲2=0+2=1+1=2+0。
13 
14 因此有3個節點時,遞歸形式爲f(3)=f(2) + f(1)*f(1) + f(2). (注意這裏的乘法,由於左右子樹一塊兒組成整棵樹,根據排列組合裏面的乘法原理便可得出)
15 
16 那麼有n個節點呢?咱們固定一個節點,那麼左右子樹的分佈狀況爲n-1=n-1 + 0 = n-2 + 1 = ... = 1 + n-2 = 0 + n-1
17 
18 OK。遞歸表達式出來了f(n) = f(n-1) + f(n-2)f(1) + f(n-3)f(2) + ... + f(1)f(n-2) + f(n-1)
19 
20  
21 
22 觀察一下這個表達式,嗯,和咱們以前見過的遞歸表達有一點區別,遞推層級爲n的時候,更多的是考慮前一步(n-1),或者前兩步(n-1)和(n-2)。
23 
24 可是這裏卻考慮到全部的狀況,即1到n-1。
25 
26 最後說明一下,這個表達式有一個學名,叫作Catalan數。上面咱們沒有定義f(0)。若是把f(0)也考慮進去,顯然沒有節點也只有一種狀況,即f(0)=1
27 
28 標準表達式爲f(n) = f(n-1)f(0) + f(n-2)f(1) + f(n-3)f(2) + ... + f(1)f(n-2) + f(n-1)f(0)
29 
30 前幾個數爲1,1,2,5,14,42,132。
31 */

應用二:

codevs 3134 Circle 

 時間限制: 1 s
 空間限制: 32000 KB
 題目等級 : 黃金 Gold
 
題目描述  Description

在一個圓上,有2*K個不一樣的結點,咱們以這些點爲端點,連K條線段,使得每一個結點都剛好用一次。在知足這些線段將圓分紅最少部分的前提下,請計算有多少種連線的方法遞歸

輸入描述  Input Description

僅一行,一個整數K(1<=K<=30)ip

輸出描述  Output Description

兩個用空格隔開的數,後者爲最少將圓分紅幾塊,前者爲在此前提下連線的方案數get

樣例輸入  Sample Input

2

樣例輸出  Sample Output

2 3

數據範圍及提示  Data Size & Hint
 1 #include<cstdio>
 2 int n;
 3 long long f;
 4 int main()
 5 {
 6     scanf("%d",&n);
 7     f=1;
 8     for(int i=2;i<=n;++i)
 9     f=f*(4*i-2)/(i+1);
10     printf("%lld %d",f,n+1);
11 /*最少的劃分部分是n條線段都不相交*/
12     return 0;
13 }
相關文章
相關標籤/搜索