题目来源: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. [每日一题2020.06.17] leetcode周赛T3 5438 制作m束花所需的最少天数 二分搜索

    题目链接 这题我开始一直在想如何在数组上dp操作搜索区间, 很蠢, 实际上用二分查找的方法可以很快的解决 首先我们通过一个函数判断第x天是否符合题意, 如果x天可以做出m束花, 那么大于m的天数必然可 ...

  2. TensorFlow从0到1之TensorFlow超参数及其调整(24)

    正如你目前所看到的,神经网络的性能非常依赖超参数.因此,了解这些参数如何影响网络变得至关重要. 常见的超参数是学习率.正则化器.正则化系数.隐藏层的维数.初始权重值,甚至选择什么样的优化器优化权重和偏 ...

  3. 面向对象存储框架:Obase快速入门

    在项目中完成对象建模后,可以使用Obase来进行对象的管理(例如对象持久化),本篇教程将创建一个.NET Core控制台应用,来展示Obase的配置和对象的增删改查操作.本篇教程旨在指引简单入门. 本 ...

  4. 使用numpy生成二维正态分布

    参考资料: https://www.zhihu.com/question/39823283?sort=created https://www.zhihu.com/question/288946037/ ...

  5. NAT网络地址转化和DHCP

    DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)通常被应用在大型的局域网络环境中,主要作用是集中的管理.分配IP地址,使网络环境中的主机动态的获得I ...

  6. 商城06——solr索引库搭建&solr搜索功能实现&图片显示问题解决

    1.   课程计划 1.搜索工程的搭建 2.linux下solr服务的搭建 3.Solrj使用测试 4.把数据库中的数据导入索引库 5.搜索功能的实现 2.   搜索工程搭建 要实现搜索功能,需要搭建 ...

  7. Maven发展历史

    1.1 Maven是什么 Maven是一个项目管理和综合工具. Maven提供了开发人员构建一个完整的生命周期框架.开发者团队可以自动完成项目的基础工具建设, Maven使用标准的目录结构和默认构建生 ...

  8. Java CRC16 MODBUS校验算法实现

    /** * CRC校验算法工具类 */ public class CRCUtil { public static String getCRC(String data) { data = data.re ...

  9. [ C++ ] 勿在浮沙筑高台 —— 内存管理(9~16p)primitives(下)

    per-class allocator 2 tips: operator new重载 不会被派生类实际使用,因为父类大小内存的分配交给子类去调用明显是不正确的.实际上会被转交至 : : operato ...

  10. Java解析apk、ipa图标,包名,应用名称,版本号

    参看:http://blog.csdn.net/moyanxuan_1993_2_24/article/details/53612001