题目来源:Trees Made to Order

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

规则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;

假设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表示二叉树的节点数,含有nodeNum节点的二叉树的第order个排列(或者形态)。

(1)、通过给定的数N计算出二叉树的节点数nodeNum。其中nodeNum=min(i|Catalan(0)+Catalan(1)+...+Catalan(i)>=N),设编号为N的二叉树是包含nodeNum个节点的二叉树的所有集合排序中的第order棵,则order=N-(Catalan(0)+Catalan(1)+...+Catalan(i-1))。

(2)、接下来是来解决这棵二叉树中左子树有多少个节点,右子树有多少节点。有题意可知,初始状态下,左子树为空,所有的节点均在右子树上并且所有节点只有右孩子;当右子树的所有节点变化完以后,将右子树中的一个节点分配给左子树,此时右子树的节点少了一个并且所有右子树的节点全部是初始化状态,依此类推。当左子树有大于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。

(3)、假设含有leftNum个左子树,rightNum个右子树的二叉树是nodeNum个节点的二叉树的第newOrder中排列(或者形态),则newOrder=order-(sum-Catalan(leftNum)*Catalan(rightNum)),其中sum=Catalan(0)*Catalan(nodeNum-1)+Catalan(1)*Catalan(nodeNum-2)+...+Catalan(leftNum)*Catalan(rightNum)。

(4)、设左子树的应该是第leftOrder的排列(或者形态),右子树则应该是的rightOrder的排列(或者形态)。其中leftOrder=(newOrder-1)/(Catalan(rightNum)+1),rightOrder=(newOrder-1)%(Catalan(rightNum)+1)。如果这个地方不太理解,请参考(2)中所提到的时钟,(Catalan(rightNum)+1)相当于60进制。

通过上面的分析,我相信大家应该能够很容易理解了吧,我当时想了大半天都没想明白,最后参考各种网上的资料才看懂,这里面包含了我所有的理解过程。不希望和我一样的菜鸟也会走我走过的路,所以与大家分享一下!如果还有什么地方不明白的,可以留言。

Java版代码(可以直接AC):

 import java.util.Scanner;

 public class Main {
static int[] catalan = {1,1,2,5,14,42,132,429,1430,4862,16796,58786,208012,
742900,2674440,9694845,35357670,129644790,477638700 }; static void split(int nodeNum, int order) {
if (nodeNum == 1) { //如果只有一个节点,直接输出,也是递归结束的条件
System.out.print('X');
return;
}
int i, sum = 0;
for (i = 0; sum < order; i++) {
sum += catalan[i] * catalan[nodeNum - i - 1];
}
i--;
int leftNum=i; //左子树的节点个数(由于为了与描述一致,所以代码写的有些累赘,不够精炼)
int rightNum=nodeNum-leftNum-1; //右子树的节点个数
int newOrder = order - (sum - catalan[leftNum] * catalan[rightNum]);
if (leftNum > 0) {
System.out.print('(');
split(leftNum, (newOrder - 1) / catalan[rightNum] + 1);
System.out.print(')');
}
System.out.print('X');
if (rightNum > 0) {
System.out.print('(');
split(rightNum, (newOrder - 1) % catalan[rightNum]+ 1);
System.out.print(')');
}
} public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
while (n != 0) {
int i, sum = 0;
for (i = 1; sum < n; i++) { //由于n=0是不做任何操作,所以i从1开始
sum += catalan[i];
}
i--;
split(i, n - (sum - catalan[i]));
n = input.nextInt();
System.out.println();
}
}
}

POJ 1095 Trees Made to Order 最详细的解题报告的更多相关文章

  1. poj 1095 Trees Made to Order

    http://poj.org/problem?id=1095 先求出n个节点数的二叉树的形态有多少种.卡特兰数f[n]=f[n-1]*(4*n-2)/(n+1);再递归求. #include < ...

  2. POJ 1095 Trees Made to Order(卡特兰数列)

    题目链接 中间计算的各种细节.有的细节没处理好,就wa了...主要思路就是根据卡特兰数列的: h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n&g ...

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

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

  4. POJ 1046 Color Me Less 最详细的解题报告

    题目来源:POJ 1046 Color Me Less 题目大意:每一个颜色由R.G.B三部分组成,D=Math.sqrt(Math.pow((left.red - right.red), 2)+ M ...

  5. POJ 1057 File Mapping 最详细的解题报告

    题目来源:POJ 1057 File Mapping 题目大意:像我的电脑那样显示文件夹和文件信息,其中在同一级目录内,文件夹排在文件的前面并且文件夹的顺序不变,同一级目录中文件按字母序排列.文件以‘ ...

  6. POJ 1063 Flip and Shift 最详细的解题报告

    题目来源:Flip and Shift 题目大意:一个椭圆形的环形容器中有黑色和白色两种盘子,问你是否可以将黑色的盘子连续的放在一起.你可以有以下两种操作: 1.顺时针旋转所有的盘子 2.顺时针旋转3 ...

  7. POJ 1047 Round and Round We Go 最详细的解题报告

    题目链接:Round and Round We Go 解题思路:用程序实现一个乘法功能,将给定的字符串依次做旋转,然后进行比较.由于题目比较简单,所以不做过多的详解. 具体算法(java版,可以直接A ...

  8. POJ 1050 To the Max 最详细的解题报告

    题目来源:To the Max 题目大意:给定一个N*N的矩阵,求该矩阵中的某一个矩形,该矩形内各元素之和最大,即最大子矩阵问题. 解题方法:最大子序列之和的扩展 解题步骤: 1.定义一个N*N的矩阵 ...

  9. [POJ 1000] A+B Problem 经典水题 C++解题报告 JAVA解题报告

        A+B Problem Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 311263   Accepted: 1713 ...

随机推荐

  1. 链式前向星存树图和遍历它的两种方法【dfs、bfs】

    目录 一.链式前向星存图 二.两种遍历方法 一.链式前向星存图:(n个点,n-1条边) 链式前向星把上面的树图存下来,输入: 9 ///代表要存进去n个点 1 2 ///下面是n-1条边,每条边连接两 ...

  2. 震惊!ConcurrentHashMap里面也有死循环,作者留下的“彩蛋”了解一下?

    JDK BUG 这篇文章,聊一下我最近才知道的一个关于 JDK 8 的 BUG 吧. 首先说一下我是怎么发现这个 BUG 的呢? 大家都知道我对 Dubbo 有一定的关注,前段时间 Dubbo 2.7 ...

  3. 将反向传播讲解的深入透彻的神一样的文章(numpy实现人工神经网络)

    为了完成机器学习课的项目,规定不许调tensorflow,pytorch这些包.可是要手工实现一个可训练的神经网络是非常困难的一件事,难点无他,就在于反向传播的实现.这不,我在网上发现了这篇文章.怎么 ...

  4. APP——python——自动化环境搭建01

    前提:python以及pycharm安装完成. ---------------------------------------------------------------------------- ...

  5. Netty源码分析之自定义编解码器

    在日常的网络开发当中,协议解析都是必须的工作内容,Netty中虽然内置了基于长度.分隔符的编解码器,但在大部分场景中我们使用的都是自定义协议,所以Netty提供了  MessageToByteEnco ...

  6. 1、struct2第一个项目登陆流程

    这些jar包的作用:第一个日志记录 第二个 使用freemarker制作页面,freemarker和jsp一样都是页面操作的 ognl是struct2提供的向el标签设置的包 struct2-core ...

  7. Python实用笔记 (16)函数式编程——偏函数

    假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去: def int2(x, base=2): re ...

  8. webpack入门进阶(1)

    1.webpack应用实例 1.1.快速上手 初始化项目 mkdir webpack-demo cd webpack-demo npm init -y 安装webpack npm i webpack@ ...

  9. Python 图像处理 OpenCV (12): Roberts 算子、 Prewitt 算子、 Sobel 算子和 Laplacian 算子边缘检测技术

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  10. P2194 HXY烧情侣【Tarjan】

    前言 当时和\(GYZ\)大佬一起做这个题,他表示这个题对他很不友好(手动滑稽) 题目描述 众所周知,\(HXY\) 已经加入了 \(FFF\) 团.现在她要开始喜(sang)闻(xin)乐(bing ...