簡介:卡特蘭數是組合數學中經常出現的一個數列。
個人覺得無論是遞推公式還是代表的含義都比斐波那契數列難理解一些。
遞推公式:
應用:
1.Cn表示長度2n的dyck word的個數。Dyck word是一個有n個X和n個Y組成的字串,且所有的前綴字串皆滿足X的個數大於等於Y的個數。以下爲長度爲6的dyck words
XXXYYY XYXXYY XYXYXY XXYYXY XXYXYY
分析:對於n個X,n個Y的排列來說一共有C(n,2n)種,還要排除其中不符合要求的排列。不符合條件的排列對於某個第2*m+1位,一定存在之前有m個X,m+1個Y,剩下的2n-2m-1位中有n-m個Y,n-m-1個X。對於所有m,它們的種類之和爲C(n+1,2n),所以Cn=C(n,2n)-C(n+1,2n),即卡特蘭數。
2.將上述X,Y換成左右括號詢問正確匹配的括號數種類是同樣的想法。
3.Cn表示在一個圓上有2n個點,用n條線把這2n個兩兩組成一隊,並且每條線不能相交,問有多少種寫法。
分析:將所有點編號爲1~2n,對於1號點,如果它與2號點相連,那麼1,2之間的連接方法爲h(0),剩餘點的連法爲h(n-1)種,如果1號點和4號點相連,1,4之間的連接方法爲h(1),剩餘h(n-2)種,所以可以推得h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0)。
具體題目:hdu 1134 http://acm.hdu.edu.cn/showproblem.php?pid=1134
4.用n個節點建立一棵二叉搜索樹(每個節點的所有左子節點都小於本身,每個節點的所有右子節點都大於本身),能建立的種類數爲h(n)種。
具體題目:hdu 1130 http://acm.hdu.edu.cn/showproblem.php?pid=1130
代碼(高精度卡特蘭數):
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string.h>
#include <ctime>
#include <ctype.h>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int ten[4]= {1,10,100,1000};
const int maxl = 300;
struct BigNumber
{
int d[maxl];
char s[maxl];
BigNumber(const char s[])
{
int len=strlen(s);
d[0]=(len-1)/4+1;
int i,j,k;
for(int i=1; i<maxl; i++)
d[i]=0;
for(int i=len-1; i>=0; i--)
{
j=(len-i-1)/4+1;
k=(len-i-1)%4;
d[j]+=ten[k]*(s[i]-'0');
}
while(d[0]>1&&d[d[0]]==0)
d[0]--;
}
BigNumber()
{
*this=BigNumber("0");
}
BigNumber(int x)
{
for (int i=0; i<maxl; i++) d[i]=0;
if (!x) d[0]=1;
while(x)
{
d[++d[0]]=x%10000;
x/=10000;
}
}
BigNumber(long long x)
{
for (int i=0; i<maxl; i++) d[i]=0;
if (!x) d[0]=1;
while(x)
{
d[++d[0]]=x%10000;
x/=10000;
}
}
void print()
{
int len=d[0];
printf("%d",d[d[0]]);
for(int i=len-1; i>=1; i--)
{
if(d[i]>=1000)
printf("%d",d[i]);
else if(d[i]>=100)
printf("0%d",d[i]);
else if(d[i]>=10)
printf("00%d",d[i]);
else printf("000%d",d[i]);
}
printf("\n");
}
void toString()
{
int top=0;
int i,j,temp;
for(i=3; i>=1; i--)
if(d[d[0]]>=ten[i])
break;
temp=d[d[0]];
for(j=i; j>=0; j--)
{
s[top++]=(char)(temp/ten[j]+'0');
temp%=ten[j];
}
for(i=d[0]-1; i>0; i--)
{
temp=d[i];
for(j=3; j>=0; j--)
{
s[top++]=(char)(temp/ten[j]+'0');
temp%=ten[j];
}
}
}
} zero=BigNumber(),d,temp,mid1[15],a[3005];
bool operator < (const BigNumber &a,const BigNumber &b)
{
if(a.d[0]!=b.d[0])
return a.d[0]<b.d[0];
int i;
for(i=a.d[0]; i>0; i--)
if(a.d[i]!=b.d[i])
return a.d[i]<b.d[i];
return false;
}
bool operator > (const BigNumber &a,const BigNumber &b)
{
if(b.d[0]!=a.d[0])
return b.d[0]<a.d[0];
int i;
for(i=b.d[0]; i>0; i--)
if(a.d[i]!=b.d[i])
return b.d[i]<a.d[i];
return false;
}
bool operator ==(const BigNumber &a,const BigNumber &b)
{
int i;
if(a.d[0]!=b.d[0])
return false;
for(i=1; i<=a.d[0]; i++)
if(a.d[i]!=b.d[i])
return false;
return true;
}
bool operator <= (const BigNumber &a,const BigNumber &b)
{
return a<b||a==b;
}
bool operator >= (const BigNumber &a,const BigNumber &b)
{
return a>b||a==b;
}
BigNumber operator +(const BigNumber &a,const BigNumber &b)
{
BigNumber c;
c.d[0]=max(a.d[0],b.d[0]);
int i,x=0;
for(i=1; i<=c.d[0]; i++)
{
x=a.d[i]+b.d[i]+x;
c.d[i]=x%10000;
x/=10000;
}
while(x!=0)
{
c.d[++c.d[0]]=x%10000;
x/=10000;
}
return c;
}
BigNumber operator -(const BigNumber &a,const BigNumber &b)
{
BigNumber c;
c.d[0]=a.d[0];
int i,x=0;
for(i=1; i<=c.d[0]; i++)
{
x=10000+a.d[i]-b.d[i]+x;
c.d[i]=x%10000;
x=x/10000-1;
}
while((c.d[0]>1)&&(c.d[c.d[0]]==0))
c.d[0]--;
return c;
}
BigNumber operator *(const BigNumber &a,const BigNumber &b)
{
BigNumber c;
c.d[0]=a.d[0]+b.d[0];
int i,j,x;
for(i=1; i<=a.d[0]; i++)
{
x=0;
for(int j=1; j<=b.d[0]; j++)
{
x=a.d[i]*b.d[j]+x+c.d[i+j-1];
c.d[i+j-1]=x%10000;
x/=10000;
}
c.d[i+b.d[0]]=x;
}
while((c.d[0]>1)&&(c.d[c.d[0]]==0))
--c.d[0];
return c;
}
bool smaller(const BigNumber &a,const BigNumber &b,int delta)
{
if(a.d[0]+delta!=b.d[0])
return a.d[0]+delta<b.d[0];
int i;
for(i=a.d[0]; i>0; i--)
if(a.d[i]!=b.d[i+delta])
return a.d[i]<b.d[i+delta];
return true;
}
void Minus (BigNumber &a,const BigNumber &b,int delta)
{
int i,x=0;
for(i=1; i<=a.d[0]-delta; i++)
{
x=10000+a.d[i+delta]-b.d[i]+x;
a.d[i+delta]=x%10000;
x=x/10000-1;
}
while((a.d[0]>1)&&(a.d[a.d[0]]==0))
a.d[0]--;
}
BigNumber operator *(const BigNumber &a,const int &k)
{
BigNumber c;
c.d[0]=a.d[0];
int i,x=0;
for(i=1; i<=a.d[0]; i++)
{
x=a.d[i]*k+x;
c.d[i]=x%10000;
x/=10000;
}
while(x>0)
{
c.d[++c.d[0]]=x%10000;
x/=10000;
}
while((c.d[0]>1)&&(c.d[c.d[0]]==0))
c.d[0]--;
return c;
}
BigNumber operator /(const BigNumber &a,const BigNumber &b)
{
BigNumber c;
d=a;
int i,j,temp;
mid1[0]=b;
for(int i=1; i<=13; i++)
mid1[i]=mid1[i-1]*2;
for(i=a.d[0]-b.d[0]; i>=0; i--)
{
temp=8192;
for(j=13; j>=0; j--)
{
if(smaller(mid1[j],d,i))
{
Minus(d,mid1[j],i);
c.d[i+1]+=temp;
}
temp/=2;
}
}
c.d[0]=max(1,a.d[0]-b.d[0]+1);
while((c.d[0]>1)&&(c.d[c.d[0]]==0))
c.d[0]--;
return c;
}
BigNumber operator %(const BigNumber &a,const BigNumber &b)
{
BigNumber c=a/b;
return a-b*c;
}
BigNumber c[105];
void init()
{
c[0]=BigNumber(1);
c[1]=BigNumber(1);
for(int i=2;i<=100;i++)
c[i]=c[i-1]*BigNumber(4*i-2)/BigNumber(i+1);
}
void solve()
{
int x;
while(scanf("%d",&x)&&~x)
{
c[x].print();
}
}
int main()
{
init();
solve();
return 0;
}