zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    C#刷遍Leetcode系列连载 索引
    C#刷遍Leetcode面试题系列连载(2): No.38
    C#刷遍Leetcode面试题系列连载(1)
    Windows新终端中玩转ASCII和Emoji游戏的正确姿势
    终于等到你!微软正式上线 Windows Terminal 预览版
    任意公众号的文中插入外链的方法找到了,亲测有效
    只需3步,即可将你的Chromium Edge 浏览器设置成中文
    重磅福利 | 知乎上赞同数最高的1000个回答2019最新版
    黑科技抢先尝(续)
    GitHub上最火爆!码代码不得不知的所有定律法则
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2908246.html
Copyright © 2011-2022 走看看