1. 程式人生 > >水題 第八站 HDU Train problem II

水題 第八站 HDU Train problem II

參考部落格 http://www.cnblogs.com/MisdomTianYa/p/6581898.html  http://www.cnblogs.com/kuangbin/archive/2012/03/21/2410519.html 卡特蘭數又稱卡塔蘭數,前幾項為1,2,5,14,42,132,429,1430.... 1. 卡特蘭數的一般項公式為 2. 另h(0)=1,h(1)=1,卡特蘭數滿足遞推式:h(n)=h(0)*h(n-1)+h(1)*h(n-2)+....+h(n-1)*h(0) (n>=2)     遞推關係的解為:h(n)=C(2n,n)/(n+1) (n=0,1,2,...) 3. 另類遞推公式:h(n)=h(n-1)*(4n-2)/(n+1)     遞推關係的另類解為:h(n)=c(2n,n)-c(2n,n+1) (n=0,1,2,...)    卡特蘭數的應用:出棧次序
      一個棧(無窮大)的進棧序列為1,2,3,…,n,有多少個不同的出棧序列?
      常規分析
      首先,我們設f(n)=序列個數為n的出棧序列種數。同時,我們假定第一個出棧的序數是k。
   第一個出棧的序數k將1~n的序列分成兩個序列,其中一個是1~k-1,序列個數為k-1,另外一個是k+1~n,序列個數是n-k。
   此時,我們若把k視為確定一個序數,那麼根據乘法原理,f(n)的問題就等價於——序列個數為k-1的出棧序列種數乘以序列個數為n - k的出棧
      序列種數,即選擇k這個序數的f(n)=f(k-1)×f(n-k)。而k可以選1到n,所以再根據加法原理,將k取不同值的序列種數相加,得到的總序列
      種數為:f(n)=f(0)f(n-1)+f(1)f(n-2)+……+f(n-1)f(0)。
   看到此處,再看看卡特蘭數的遞推式,答案不言而喻,即為f(n)=h(n)= C(2n,n)/(n+1)= c(2n,n)-c(2n,n+1)(n=1,2,3,……)。
    最後,令f(0)=1,f(1)=1。
凸多邊形三角劃分
  在一個凸多邊形中,通過若干條互不相交的對角線,把這個多邊形劃分成了若干個三角形。現在的任務是鍵盤上輸入凸多邊形的邊數n,求不同劃分的方案數f(n)。比如當n=6時,f(6)=14。[6]
       分析 :如果純粹從f(4)=2,f(5)=5,f(6)=14,……,f(n)=n慢慢去歸納,恐怕很難找到問題的遞推式,我們必須從一般情況出發去找規 
律。因為凸多邊形的任意一條邊必定屬於某一個三角形,所以我們以某一條邊為基準,以這條邊的兩個頂點為起點P1和終點Pn(Point),將該凸多邊形的頂點依序標記為P1、P2、……、Pn,再在該凸多邊形中找任意一個不屬於這兩個點的頂點Pk(2<=k<=n-1),來構成一個三角形,用這個三角形把一個凸多邊形劃分成兩個凸多邊形,其中一個凸多邊形,是由P1,P2,……,Pk構成的凸k邊形(頂點數即是邊數),另一個凸多邊形,是由Pk,Pk+1,……,Pn構成的凸n-k+1邊形。此時,我們若把Pk視為確定一點,那麼根據乘法原理,f(n)的問題就等價於——凸k多邊形的劃分方案數乘以凸n-k+1多邊形的劃分方案數,即選擇Pk這個頂點的f(n)=f(k)×f(n-k+1)。而k可以選2到n-1,所以再根據加法原理,將k取不同值的劃分方案相加,得到的總方案數為:f(n)=f(2)f(n-2+1)+f(3)f(n-3+1)+……+f(n-1)f(2)。看到此處,再看看卡特蘭數的遞推式,答案不言而喻,即為f(n)=h(n-1) (n=2,3,4,……)。最後,令f(2)=1,f(3)=1。
卡特蘭數模板
//h( n ) = ( ( 4*n-2 )/( n+1 )*h( n-1 ) );


#include<stdio.h>

//*******************************
//打表卡特蘭數
//第 n個 卡特蘭數存在a[n]中,a[n][0]表示長度;
//注意數是倒著存的,個位是 a[n][1] 輸出時注意倒過來。 
//*********************************
int a[105][100];
void ktl()
{
    int i,j,yu,len;
    a[2][0]=1;
    a[2][1]=2;
    a[1][0]=1;
    a[1][1]=1;
    len=1;
    for(i=3;i<101;i++)
    {
        yu=0;
        for(j=1;j<=len;j++)
        {
            int t=(a[i-1][j])*(4*i-2)+yu;
            yu=t/10;
            a[i][j]=t%10;
        }    
        while(yu)
        {
            a[i][++len]=yu%10;
            yu/=10;
        }
        for(j=len;j>=1;j--)
        {
            int t=a[i][j]+yu*10;
            a[i][j]=t/(i+1);
            yu = t%(i+1);
        }        
        while(!a[i][len])
        {
            len--;
        }    
        a[i][0]=len;
    }    
    
}    
int main()
{
    ktl();
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=a[n][0];i>0;i--)
        {
            printf("%d",a[n][i]);
        }    
        puts("");
    }    
    return 0;
}