卡特兰数列公式证明:
问题大意是用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的序列。反过来,对每个(n+1)个S和(n-1)个X的序列,我们都能逆转这个过程,而且找出导致它的前一种类型的不允许序列。例如XXSXSSSXXSSS必然来自SSXSXXXXXSSS。这个对应说明,不允许的序列的个数是c(2n, n-1),因此a(n) = c(2n, n) - c(2n, n-1)。 即a(n) = c(2n, n)/(n+1)。 递推公式a(n)=a(n-1)*(4*n-2)/(n+1);
具体为什么二叉树枚举是属于卡特兰数列,我也不知道,也找不到证明方法。
除此之外,此题还需要高精度。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string.h>
#define base 10000
#define maxn 100
using namespace std;
int num[105][100];
void multiply(int a[],int b)
{
int i,temp = 0;
for(i = maxn - 1; i >= 0; i--)
{
temp += a[i]*b;
a[i] = temp%base;
temp /= base;
}
}
void dive(int a[],int b)
{
int i,temp = 0;
for(i = 0; i < maxn; i++)
{
temp = temp*base + a[i];
a[i] = temp / b;
temp %= b;
}
}
int main()
{
int i,n;
memset(num,0,sizeof(num));
num[1][maxn-1] = 1;
for(i = 2; i <= 100;i++)
{
memcpy(num[i],num[i-1],maxn*sizeof(int));
multiply(num[i],4*i-2);
dive(num[i],i+1);
}
while(~scanf("%d",&n))
{
i = 0;
while(num[n][i] == 0)i++;
printf("%d",num[n][i++]);
for(; i < maxn; i++)
{
printf("%04d",num[n][i]);
}
printf("\n");
}
return 0;
}