POJ 1095 Trees Made to Order 最详细的解题报告
题目来源: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 最详细的解题报告的更多相关文章
- poj 1095 Trees Made to Order
http://poj.org/problem?id=1095 先求出n个节点数的二叉树的形态有多少种.卡特兰数f[n]=f[n-1]*(4*n-2)/(n+1);再递归求. #include < ...
- 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 ...
- poj 1095 Trees Made to Order 卡特兰数
这题用到了卡特兰数,详情见:http://www.cnblogs.com/jackge/archive/2013/05/19/3086519.html 解体思路详见:http://blog.csdn. ...
- POJ 1046 Color Me Less 最详细的解题报告
题目来源:POJ 1046 Color Me Less 题目大意:每一个颜色由R.G.B三部分组成,D=Math.sqrt(Math.pow((left.red - right.red), 2)+ M ...
- POJ 1057 File Mapping 最详细的解题报告
题目来源:POJ 1057 File Mapping 题目大意:像我的电脑那样显示文件夹和文件信息,其中在同一级目录内,文件夹排在文件的前面并且文件夹的顺序不变,同一级目录中文件按字母序排列.文件以‘ ...
- POJ 1063 Flip and Shift 最详细的解题报告
题目来源:Flip and Shift 题目大意:一个椭圆形的环形容器中有黑色和白色两种盘子,问你是否可以将黑色的盘子连续的放在一起.你可以有以下两种操作: 1.顺时针旋转所有的盘子 2.顺时针旋转3 ...
- POJ 1047 Round and Round We Go 最详细的解题报告
题目链接:Round and Round We Go 解题思路:用程序实现一个乘法功能,将给定的字符串依次做旋转,然后进行比较.由于题目比较简单,所以不做过多的详解. 具体算法(java版,可以直接A ...
- POJ 1050 To the Max 最详细的解题报告
题目来源:To the Max 题目大意:给定一个N*N的矩阵,求该矩阵中的某一个矩形,该矩形内各元素之和最大,即最大子矩阵问题. 解题方法:最大子序列之和的扩展 解题步骤: 1.定义一个N*N的矩阵 ...
- [POJ 1000] A+B Problem 经典水题 C++解题报告 JAVA解题报告
A+B Problem Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 311263 Accepted: 1713 ...
随机推荐
- (二)groupId和artifactId
groupId一般分为多个段,这里我只说两段,第一段为域,第二段为公司名称. 域又分为org.com.cn等等许多,其中org为非营利组织,com为商业组织. 举个apache公司的tomcat项目例 ...
- beego register db `default`, sql: unknown driver "mysql" (forgotten import?)
首先先去你的目录下找找这个文件里有没有东西,或者有没有这个文件 如果没有 执行下面两个命令: 下载:go get github.com/Go-SQL-Driver/MySQL 安装:go instal ...
- PDO的事务处理 事务回滚
<?phpheader('content-type:text/html;charset=utf-8');include 'PdoClass.php';$objPdo=new PdoClass() ...
- WeChair Plus版项目介绍
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 团队名称 WeChair 这个作业要求在哪里 团队作业第一次:团队作业第一次(2) 这个作业的目标 项目介绍,项目修改 作业正文 ...
- 跟着whatwg看一遍事件循环
前言 对于单线程来说,事件循环可以说是重中之重了,它为任务分配不同的优先级,井然有序的调度.让js解析,用户交互,页面渲染等互不冲突,各司其职. 我们书写的代码无时无刻都在和事件循环打交道,要想写出更 ...
- Python 简明教程 --- 15,Python 函数
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 测试只能证明程序有错误,而不能证明程序没有错误. -- Edsger Dijkstra 目录 本节我 ...
- py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.collectAndServe. : java.lang.IllegalArgumentException: Unsupported class file major version 55
今天小编用Python编写Spark程序报了如下异常: py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apach ...
- 2020 最新省市区 sql
一个基于有赞的 area.js 生成的sql area.js 简单的写了一个js 生成了sql语句 sql文件 完整代码
- GitHub 热点速览 Vol.26:手把手带你做数据库
作者:HelloGitHub-小鱼干 摘要:手把手带你学知识,应该是学习新知识最友好的姿势了.toyDB 虽然作为一个"玩具"项目不能应用在实际开发中,但通过它你可以了解到如何制作 ...
- 一文说通MongoDB via Python操作
Python并不仅仅是一个做Machine Learning的语言. 说到Python,一般都会感觉它关联着ML,如果不是做ML开发,就会觉得离自己很远.而实际上,作为一门语言,Python在应用 ...