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 ...
随机推荐
- 【Java入门】JDK安装和环境变量配置(Win7版)
系统环境:Windows7 x64 安装JDK和JRE版本:1.8.0_191 1.下载JDK安装包 Oracle官网下载网址:https://www.oracle.com/technetwork/j ...
- python工业互联网应用实战2—从需求开始
前言:随着国家工业2025战略的推进,工业互联网发展将会提速,将迎来一个新的发展时期,越来越多的企业开始逐步的把产线自动化,去年年底投产的小米亦庄的智能工厂就是一个热议的新闻.小米/华为智能工厂只能说 ...
- 【JMeter_03】JMeter GUI操作界面介绍
JMeter主界面主要分为 标题栏.菜单栏.工具栏.测试计划树形目录.内容展示区 标题栏:主要展示JMeter的程序版本.当前脚本的名称.脚本的储存路径 菜单栏:程序基本上所有功能的所属分类目录,基本 ...
- 基于flask的城市空气质量分析系统
1.1 系统功能 在对主要需求进行分析后,确定系统由以下几个模块组成. 1) 用户信息管理: 该部分主要完成系统管理员的增加.删除.编辑和访问控制权限等操作. 2) 数据管理: 该部分主要完成后台存 ...
- URL is not registered (Settings | Languages & Frameworks | Schemas and DTDs)
File - Settings - Schemas and DTDS时,选中报错的地址,然后Ctrl+alt+s打开设置(或者右键 -> setting)找到 把报错的地址填入就可以了,最后应用 ...
- jni不通过线程c回调java的函数 --总结
1.JNIEnv类型是一个指向全部JNI方法的指针.该指针只在创建它的线程有效,不能跨线程传递 2.JavaVM是虚拟机在JNI中的表示,一个JVM中只有一个JavaVM对象,这个对象是线程共享的. ...
- Python3-logging模块-日志记录
Python3中的logging模块提供了较为灵活的事件日志系统 日志级别 DEBUG < INFO < WARING(Python默认) < ERROR < FATAL(CR ...
- 解决UEditor编辑时,只添加视频内容,不添加文字,视频信息不能保存到数据库的问题
造成这个问题的原因是富文本保存内容时会筛除空标签,然后统计是否有内容,通过字数统计也可以看到,上传完视频后字数还是零,因为视频上传后是<video></video>标签,这个标 ...
- openstack迁移计算节点所有云主机
迁移计算节点所有云主机 -------高德置地 王锦雄 使用host-evacuate-live热迁移主机 查看主机目前的云主机情况 nova hypervisor-servers cloud1 ...
- Windows Defender might be impacting your build performance
由于换了SSD, 昨天安装了最新的 Idea 2019.2+ , 然后发现每次导入项目都有如下提示: 处理方法就是在Windows安全中心排除目录 处理方式参考: 官方 Known issues An ...