Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 7155   Accepted: 4094

Description

We can number binary trees using the following scheme: 
The empty tree is numbered 0. 
The single-node tree is numbered 1. 
All binary trees having m nodes have numbers less than all those having m+1 nodes. 
Any binary tree having m nodes with left and right subtrees L and R is numbered n such that all trees having m nodes numbered > n have either Left subtrees numbered higher than L, or A left subtree = L and a right subtree numbered higher than R.

The first 10 binary trees and tree number 20 in this sequence are shown below: 

Your job for this problem is to output a binary tree when given its order number. 

Input

Input consists of multiple problem instances. Each instance consists of a single integer n, where 1 <= n <= 500,000,000. A value of n = 0 terminates input. (Note that this means you will never have to output the empty tree.)

Output

For each problem instance, you should output one line containing the tree corresponding to the order number for that instance. To print out the tree, use the following scheme:

A tree with no children should be output as X. 
A tree with left and right subtrees L and R should be output as (L’)X(R’), where L’ and R’ are the representations of L and R. 
If L is empty, just output X(R’). 
If R is empty, just output (L’)X. 

Sample Input

1 20 31117532 0

Sample Output

X ((X)X(X))X (X(X(((X(X))X(X))X(X))))X(((X((X)X((X)X)))X)X)

题目大意:根据下面的规则给一棵二叉树编号:

规则1:如果二叉树为空,则编号为0;

规则2:如果二叉树只有一个节点,则编号为1;

规则3:所有含有m个节点的二叉树的编号小于所有含有m+1个节点的二叉树的编号;

规则4:如果一棵含有m个节点的二叉树(左子树为L,右子树为R)的编号为n,要想其它含有m个节点的二叉树的编号如果大于n,则需要满足两个条件中的任意一个:1、左子树的编号大于L的编号;2、左子树的编号等于L的编号,但是右子树的编号大于R的编号。

解题方法:卡特兰数列(Catalan)+递归

Catalan数列简介:令Catalan(0)=1,Catalan(1)=1,Catalan数列满足地推公式:

Catalan(n)=Catalan(0)*Catalan(n-1)+Catalan(1)*Catalan(n-2)+...+Catalan(n-1)*Catalan(0),其中n>=2;

catalan数在这道题的理解,简单的来说就是一个节点数为n的二叉树的形态的个数,即为划分的个数

详情移步:Catalan卡塔兰数

假设f(n)表示n个节点的二叉树的所有顺序,由于左子树和右子树的顺序是相互独立的,假设0<=i<=n:表示左子树有i个节点,则右子树有n-i-1个节点(要除去根节点),则含有n个节点的二叉树,当左子树含有i个节点时,二叉树的节点顺序树为:f(i)*f(n-i-1),i从0到n-1 ,然后累加就可以求出所有f(n). 这就是一点典型的Catalan数列问题。

解题思路:

split(NodeNum,order)是用于打印问题的解的函数,其中NodeNum为当前树的结点数,order为当前树在 节点数为NodeNum的所有树中 的序号(即位次)。

(1)首先,递归框架:

 /*
递归划分结构框架
*/
void split(int NodeNum,int order)
{//NodeNum为当前子树结点数,order为当前子树在节点数为NodeNum时的序号
if(NodeNum == ) //节点数为1 直接输出X 作为递归结束条件
{cout<<"X";return;}
else
{
if(LeftNum>)//左子树不为空
{
cout<<"(";
split(,);
cout<<")";
}
cout<<"X";//打印父节点X
if(RightNum>)
{
cout<<"(";
split(,);
cout<<")";
}
}
}

NodeNum=1为递归边界条件,表示这棵子树只有一个结点,打印该结点,并返回。

(2) 计算节点数为NodeNum,序号为order的树的左右子树有多少结点,即计算LeftNum和RightNum。

由题意可知,序号为1的左子树为空,右子树结点数为order,且为右斜树(所有的节点均在右子树上并且所有节点只有右孩子);左右子树变换形态,此时左子树为空,右子树的形态数为catalan[order];当右子树遍历完所有形态后,左子树节点数加一,右子树节点数减一,生成初始状态依然为右子树为右斜树,此时左子树有节点,也为右斜树(当然此时只有一个节点,即只有根节点);左右子树变化形态,左子树形态数1,右子树形态数catalan[order-1];左子树节点数+1,右子树节点数-1,依此类推。

  当左子树有大于1个结点时,设为i个,左子树有catalan[i]种形态,左子树的每一种形态下,右子树节点数为NodeNum-i-1,形态数catalan[NodeNum-i-1]。

  整个过程就像一个时钟计时一样,左子树是时针,右子树是分针,右子树全部变化完,左子树加1,但是与时钟不同的是:时钟是60进制的,二右子树是catalan[i]进制的,i会逐渐变为0。由此可以得出二叉树中左子树的节点数LeftNum: leftNum=min(i|catalan[0]*catalan[nodeNum-1]+catalan[1]*catalan[nodeNum-2]+...+catalan[i]*catalan[NodeNum-i-1]>=order),右子树的节点数RightNum=NodeNum-LeftNum-1。

  假设  所要求的树为  含有LeftNum个结点的左子树,RightNum个结点的右子树的二叉树是NodeNum个节点的二叉树  的第NewOrder棵树,则NewOrder=order-sum,其中sum=catalan(0)*catalan(NodeNum-1)+catalan(1)*catalan(NodeNum-2)+...+catalan(LeftNum-1)*catalan(RightNum+1)。

  设左子树的应该是节点数为LeftNum的树的第LeftOrder个形态,右子树则应该是是节点数为RightNum的树的RightOrder个形态。其中LeftOrder=(NewOrder-1)/catalan(RightNum)+1,RightOrder=(NewOrder-1)%catalan(RightNum)+1。

  此处应注意模数

 #include<iostream>
using namespace std;
long catalan[] = {,,,,,,,,,,,,,
,,,,,};
void split(int NodeNum,int order)
{
if(NodeNum == ) {cout<<"X";return;}
else
{ int sum=;
int i;
for(i=;sum<order;i++)
{
sum += catalan[i]*catalan[NodeNum-i-];
}
int LeftNum = --i;//左子树的节点个数
int RightNum = NodeNum-LeftNum-;//右子树节点个数
sum = sum - catalan[LeftNum]*catalan[RightNum];
long NewOrder = order-sum;
if(LeftNum>)
{
cout<<"(";
split(LeftNum,(NewOrder-)/catalan[RightNum]+);
cout<<")";
}
cout<<"X";
if(RightNum>)
{
cout<<"(";
split(RightNum,(NewOrder-)%catalan[RightNum]+);
cout<<")";
}
}
}
int main()
{
long n;//n是序号 while(cin>>n)
{
if(n == ) return ;//0为结束
else
{
//首先得判断有几个结点
int i,sum=;
for(i=;sum<n;i++)//由于i=0不做任何操作,所以,从1开始
{
sum+=catalan[i];
}
i--;sum = sum-catalan[i];
//然后进行递归调用
split(i,n-sum);//i个结点的第n-sum种情况
}
cout<<endl; }
return ;
}

Trees Made to Order——Catalan数和递归的更多相关文章

  1. poj 1095 Trees Made to Order 卡特兰数

    这题用到了卡特兰数,详情见:http://www.cnblogs.com/jackge/archive/2013/05/19/3086519.html 解体思路详见:http://blog.csdn. ...

  2. Catalan数 && 【NOIP2003】出栈序列统计

    令h(1)=1, h(0)=1,catalan数满足递归式: h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)h(0) (n>=2) =C(2n, n)/(n+1) ...

  3. 卡特兰数 Catalan数 ( ACM 数论 组合 )

    卡特兰数 Catalan数 ( ACM 数论 组合 ) Posted on 2010-08-07 21:51 MiYu 阅读(13170) 评论(1)  编辑 收藏 引用 所属分类: ACM ( 数论 ...

  4. 【集训笔记】【大数模板】特殊的数 【Catalan数】【HDOJ1133【HDOJ1134【HDOJ1130

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3324 http://blog.csdn.net/xymscau/artic ...

  5. catalan 数——卡特兰数(转)

    Catalan数——卡特兰数 今天阿里淘宝笔试中碰到两道组合数学题,感觉非常亲切,但是笔试中失踪推导不出来后来查了下,原来是Catalan数.悲剧啊,现在整理一下 一.Catalan数的定义令h(1) ...

  6. Catalan数——卡特兰数

    一.Catalan数的定义 令h(0)=1,h(1)=1,Catalan数满足递归式:h(n) = h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)*h(0)  (n& ...

  7. (转载)Catalan数——卡特兰数

    Catalan数——卡特兰数 今天阿里淘宝笔试中碰到两道组合数学题,感觉非常亲切,但是笔试中失踪推导不出来后来查了下,原来是Catalan数.悲剧啊,现在整理一下 一.Catalan数的定义令h(1) ...

  8. hdu 1130 How Many Trees?(Catalan数)

    How Many Trees? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  9. POJ 1095 Trees Made to Order 最详细的解题报告

    题目来源:Trees Made to Order 题目大意:根据下面的规则给一棵二叉树编号: 规则1:如果二叉树为空,则编号为0: 规则2:如果二叉树只有一个节点,则编号为1: 规则3:所有含有m个节 ...

随机推荐

  1. selenium在爬虫中的应用之动态数据爬取

    一.selenium概念 selenium 是一个基于浏览器自动化的模块 selenium爬虫之间的关联: 1.便捷的获取动态加载的数据 2.实现模拟登录 基本使用 pip install selen ...

  2. sql server 语句书写注意事项

    1  Between在某些时候比IN 2 在必要是对全局或者局部临时表创建索引,有时能够提高速度,但不是一定会这样,因为索引也耗费大量的资源.他的创建同是实际表一样 3 尽量少用视图,它的效率低.对视 ...

  3. 如何确定asp.net请求生命周期的当前处理事件

    1 首先在全局应用程序里面添加如下代码 using System; using System.Collections.Generic; using System.Linq; using System. ...

  4. SCRUM 是一个用于开发和维护复杂产品的框架

    转自:http://www.scrumcn.com/agile/scrum-knowledge-library/scrum.html#tab-id-1 Scrum 是一个用于开发和维护复杂产品的框架 ...

  5. 关于select的困惑

    困惑 首先,我知道select是IO复用.以UDP为例,select流程大体如下: for(;;) { //通过FD_SET告诉内核你感兴趣的fd fd_set read_fds; FD_CLEAR( ...

  6. 调查问卷WebApp

    1. 效果演示 2. 主要知识点 使用slot分发内容 动态组件 组件通信 实例的生命周期 表单 3. 遇到的问题 bus 通信 第一次 $on 监听不到 // 解决bus 第一次通信 $on 监听不 ...

  7. Spring入门篇——第1章 概述

    第1章 概述 本章对课程的情况进行介绍,并介绍框架和Spring概况. 1-1 Spring入门课程简介 1-2 Spring概况 1-3 Spring框架

  8. mysqldump表损坏问题

    遇到的问题:mysqldump: Error 1194: Table 'user' is marked as crashed and should be repaired when dumping t ...

  9. 第四章 Jinja2模版

    模板简介: 在之前的章节中,视图函数只是直接返回文本,而在实际生产环境中的页面大多是带有样式和复杂逻辑的HTML代码,这可以让浏览器渲染出非常漂亮的页面.目前市面上有非常多的模板系统,其中最知名好用的 ...

  10. SpringMVC拦截静态资源的解决方法

    本文中的各软件版本简要信息: IDE:Myeclise17 JDK:1.8.0_111 spring:5.1.8 springMVC:5.1.8 mybatis:3.2.2 Tomcat:9.0 在使 ...