uva 10303 How Many Trees?

组合数学,递推(Catalan number , 卡特兰数)

题目:给n个数字,能构建成多少种二叉排序树。这个问题并不难,用递归的思想就能解决。当空树即n=0时方案数为1,当n=1时方案数同样为1。当n>=2时,我们把n个数按升序排列,如果我们选ai作为数树根,那么a1……ai-1必定在有子树,ai+1……an必定在左子树,左子树有i-1个元素,同样是排序二叉树,相当于问这个i-1个元素又能组成多少个二叉排序树,右子树有n-i个元素,同时是二叉排序树,相当于问这n-i个元素能组成多少个二叉排序树,方案数为两者相乘。

对于每个ai作为树根的计算方法如上,而所有的ai都能作为树根,所以不能总结出公式

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)

由于n去到1000,是个很大的数,要用到高进度

但是发现用上面的公式去推必须为二重循环,会超时,所以没办法去找报告,才知道这个数列其实是卡特兰数,然后查了卡特兰数的相关资料,得到了不同的递推公式,下面这个递推公式就是正解

h(n)=h(n-1)*(4*n-2)/(n+1);

 

 

用这个公式,高精度乘法为int乘高精度,高精度除法为int除高精度,还是比较好写的

#include <cstdio>
#include <cstring>

#define N 2000

int maxlen;
struct num
{
    int a[N+50],len;
}big[N];

void add(struct num &p ,struct num t)
{
    int max=p.len>t.len?p.len:t.len;
    int i,c=0;
    for(i=0; i<max; i++)
    { p.a[i]+=(t.a[i]+c); c=p.a[i]/10; p.a[i]%=10;}
    if(c) p.a[i++]=c;
    p.len=i;
}

void mul(struct num &p , struct num q , int x)
{
   int s;
   for(int i=0; i<q.len; i++)
   {
       s=q.a[i]*x;
       struct num t;
       int j=i;
       memset(t.a,0,sizeof(t.a)); t.len=0;
       while(s)
       { t.a[j]=s%10; s/=10; j++; }
       t.len=j;
       add(p,t);
   }
}

void div(struct num &p , int y)
{
    int i=p.len-1, x=0 , k=0 , j;
    int ans[N+50];
    memset(ans,0,sizeof(ans));
    while(i>=0)
    {
        while(x<y && i>=0)
        { x=(x*10+p.a[i]); i--; ans[k++]=0; }
        k--;
        ans[k++]=x/y;
        x%=y;
    }

    for(i=0; ;i++) if(ans[i]) break;  //消除前导0
    for(p.len=k-i , j=p.len-1; i<k ; j--,i++) p.a[j]=ans[i];
}
int main()
{
    memset(big,0,sizeof(big));
    big[0].a[0]=1; big[0].len=1;
    big[1].a[0]=1; big[1].len=1;

    for(int n=2; n<=1000; n++)
    {
        //h(n)=h(n-1)*(4*n-2)/(n+1)
        mul(big[n] , big[n-1] , 4*n-2);
        div(big[n] , n+1);
    }

    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=big[n].len-1; i>=0; i--)
            printf("%d",big[n].a[i]);
        printf("\n");
    }
    return 0;
}

 

posted @ 2013-02-06 23:54  Titanium  阅读(538)  评论(1编辑  收藏  举报