EOJ1850 大整数 卡特兰数

题目:

HowMany Trees?

 

TimeLimit:1000MS Memory Limit:30000KB

TotalSubmit:376 Accepted:160

 

Description

 

Abinary search tree is a binary tree with root k such that any node v reachablefrom its left has label (v) <label (k) and any node w reachable from itsright has label (w) > label (k). It is a search structure which can find anode with label x in O(n log n) average time, where n is the size of the tree(number of vertices).

 

Givena number n, can you tell how many different binary search trees may beconstructed with a set of numbers of size n such that each element of the setwill be associated to the label of exactly one node in a binary search tree?

 

Input

 

Theinput will contain a number 1 <= i <= 100 per line representing thenumber of elements of the set.

 

Output

 

Youhave to print a line in the output for each entry with the answer to theprevious question.

 

SampleInput

 

1

2

3

 

SampleOutput

 

1

2

5

 

Source

 

Uva

 

题目分析:

     根据题意,只要确定了父节点,左右子树的节点数便确定了。因此可以依次枚举父节点编号,把所有情况累加,注意到树的递归定义,本题也可采用递归(或递推)的思想计算树的构造方法数。其实本题得出数据为卡特兰数列,同时还应注意到本题需要使用大整数的乘法和加法;

方法二:直接套用公式,需要使用大整数除法和乘法。

 

注意事项:

1.       乘法算法的效率问题:因为本题多次做乘法,在不计时间代价的前提下得出答案后还应根据答案适当减少用于存储数据的空间,这样可以减小两次for循环的执行次数,从而提高效率。

 

代码:

 

#include <iostream>

#include <cstring>

#include <string>

#include <cstdio>

 

using namespace std;

 

struct Num                                   //大整数类

{

   int num[200]={};

   Num(){memset(num,0,sizeof(num));}

   Num(const string &s)                //将数据倒置存放

    {

       int k=0;

       int len=s.size();

       for(int i=len-1;i>=0;--i)

       {

           num[k++]=(s[i]-'0');

       }

    }

   void print()

    {

       int i;

       for(i=70;i>=0;--i)                //去除前倒0

       {

           if(num[i])

                break;

       }

       for(;i>=0;--i)

       {

           printf("%d",num[i]);

       }

       printf("\n");

    }

};

 

Num operator+(const Num &a,const Num&b)

{

   Num c;

   int i;

   for(i=0;i<70;++i)

    {

       c.num[i]=a.num[i]+b.num[i];

    }

   for(i=0;i<70;++i)

    {

       c.num[i+1]+=c.num[i]/10;

       c.num[i]%=10;

    }

   return c;

}

 

Num operator*(const Num &a,const Num&b)

{

   Num ans;

   int i,j;

   for(i=0;i<70;++i)                 //此处可先将循环次数设较大,根据得出答案后在根据答案长度

    {                                             //缩小循环次数,否则容易超时。

       for(j=0;j<70;++j)

        {

           ans.num[i+j]+=a.num[i]*b.num[j];

       }

    }

   for(i=0;i<105;++i)

    {

       ans.num[i+1]+=ans.num[i]/10;

       ans.num[i]%=10;

    }

   return ans;

}

 

int main()

{

   /*Numf0={"1"},f1={"1"},f2={"2"},f3={"5"},f4={"14"};              //测试类正确性

   Num f5=f4*f0+f3*f1+f2*f2+f1*f3+f0*f4;

   f5.print();*/

   Num f[102];

   f[0]={"1"};

   f[1]={"1"};

   f[2]={"2"};

   f[3]={"5"};

   int i,j;

   for(i=4;i<101;++i)

    {

       for(j=0;j<i;++j)

       {

           f[i]=f[i]+f[j]*f[i-1-j];

       }

    }

   int n;

   /*for(i=1;i<101;++i)                             //测试输出速度,是否会超时等

       f[i].print();*/

   while(~scanf("%d",&n))

    {

       f[n].print();

    }

   return 0;

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值