多邊形劃分-卡特蘭數
區域賽系列一多邊形劃分
時間限制:1000 ms | 記憶體限制:65535 KB 難度:2- 描述
-
Give you a convex(凸邊形), diagonal n-3 disjoint divided into n-2 triangles(直線), for different number of methods, such as n=5, there are 5 kinds of partition method, as shown in Figure
- 輸入
- The first line of the input is a n (1<=n<=1000), expressed n data set. The next n lines each behavior an integer m (3<=m<=18), namely the convex edges.
- 輸出
- For each give m,, output how many classification methods. example output: Case #a : b
- 樣例輸入
-
3 3 4 5
- 樣例輸出
-
Case #1 : 1 Case #2 : 2 Case #3 : 5
卡特蘭數:
卡塔蘭數是組合數學中一個常出現在各種計數問題中出現的數列。由以比利時的數學家歐仁·查理·卡塔蘭 (1814–1894)命名。
卡塔蘭數的一般項公式為 另類遞迴式: h(n)=((4*n-2)/(n+1))*h(n-1);
令h(0)=1,h(1)=1,catalan數滿足遞迴式:
h(n)= h(0)*h(n-1) + h(1)*h(n-2) + + h(n-1)h(0) (其中n>=2)
另類遞迴式: h(n)=((4*n-2)/(n+1))*h(n-1);
最典型的四類應用:(實質上卻都一樣,無非是遞迴等式的應用,就看你能不能分解問題寫出遞迴式了)
1.括號化問題。
矩陣鏈乘: P=a1×a2×a3×……×an,依據乘法結合律,不改變其順序,只用括號表示成對的乘積,試問有幾種括號化的方案?(h(n)種)
2.出棧次序問題。
一個棧(無窮大)的進棧序列為1,2,3,..n,有多少個不同的出棧序列?
類似:
(1)有2n個人排成一行進入劇場。入場費5元。其中只有n個人有一張5元鈔票,另外n人只有10元鈔票,劇院無其它鈔票,問有多少中方法使得只要有10元的人買票,售票處就有5元的鈔票找零?(將持5元者到達視作將5元入棧,持10元者到達視作使棧中某5元出棧)
(2)在圓上選擇2n個點,將這些點成對連線起來,使得所得到的n條線段不相交的方法數。
3.將多邊行劃分為三角形問題。
將一個凸多邊形區域分成三角形區域的方法數?
類似:一位大城市的律師在她住所以北n個街區和以東n個街區處工作。每天她走2n個街區去上班。如果她
從不穿越(但可以碰到)從家到辦公室的對角線,那麼有多少條可能的道路?
類似:在圓上選擇2n個點,將這些點成對連線起來使得所得到的n條線段不相交的方法數?
4.給頂節點組成二叉樹的問題。
給定N個節點,能構成多少種形狀不同的二叉樹?
(一定是二叉樹!
先去一個點作為頂點,然後左邊依次可以取0至N-1個相對應的,右邊是N-1到0個,兩兩配對相乘,就是h(0)*h(n-1) + h(2)*h(n-2) + + h(n-1)h(0)=h(n))
(能構成h(N)個)
5,問題描述:
12個高矮不同的人,排成兩排,每排必須是從矮到高排列,而且第二排比對應的第一排的人高,問排列方式有多少種?
我們先把這12個人從低到高排列,然後,選擇6個人排在第一排,那麼剩下的6個肯定是在第二排.
用0表示對應的人在第一排,用1表示對應的人在第二排,那麼含有6個0,6個1的序列,就對應一種方案.
比如000000111111就對應著
第一排:0 1 2 3 4 5
第二排:6 7 8 9 10 11
010101010101就對應著
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
問題轉換為,這樣的滿足條件的01序列有多少個。
觀察1的出現,我們考慮這一個出現能不能放在第二排,顯然,在這個1之前出現的那些0,1對應的人
要麼是在這個1左邊,要麼是在這個1前面。而肯定要有一個0的,在這個1前面,統計在這個1之前的0和1的個數。
也就是要求,0的個數大於1的個數。
OK,問題已經解決。
如果把0看成入棧操作,1看成出棧操作,就是說給定6個元素,合法的入棧出棧序列有多少個。
這就是catalan數,這裡只是用於棧,等價地描述還有,二叉樹的列舉、多邊形分成三角形的個數、圓括弧插入公式中的方法數,其通項是c(2n, n)/(n+1)。
程式碼:
#include<stdio.h>
long long num[25];
int main()
{
int t,step=1;
scanf("%d",&t);
num[0]=1,num[1]=1,num[2]=2;
for(int i=3;i<=18;i++)
{
long long sum=0,j=1;
while(j<=i)
{
sum+=num[i-j]*num[j-1];
j++;
}
num[i]=sum;
}
// for(int i=1;i<=8;i++)
// {
// printf("%lld\n",num[i]);
// }
while(t--)
{
int n;
scanf("%d",&n);
printf("Case #%d : %lld\n",step++,num[n-2]);
}
return 0;
}