[SDOI2008]红黑树(TREE) 个人题解

题干如下:

红黑树是一类特殊的二叉搜索树,其中每个结点被染成红色或黑色。若将二叉搜索树结点中的空指针看作是指向一个空结点,则称这类空结点为二叉搜索树的前端结点。并规定所有前端结点的高度为-1。 

一棵红黑树是满足下面“红黑性质”的染色二叉搜索树:

(1) 每个结点被染成红色或黑色;

(2) 每个前端结点为黑色结点;

(3) 任一红结点的子结点均为黑结点;

(4) 在从任一结点到其子孙前端结点的所有路径上具有相同的黑结点数。 

从红黑树中任一结点x出发(不包括结点x),到达一个前端结点的任意一条路径上的黑结点个数称为结点x的黑高度,记作bh(x)。红黑树的黑高度定义为其根结点的黑高度。

给定正整数N,试设计一个算法,计算出在所有含有N个结点的红黑树中,红色内结点个数的最小值和最大值。  

输入描述:

输入共一个数N。

输出描述:

输出共两行。

第一行为红色内结点个数的最小值,第二行为最大值。

示例1

输入

8

输出

1 4


题解部分:

先贴代码,使用py:

n=int(input())
k=n+1
str_k=bin(k)
_min=0
for _ in str_k:
    if _ == '1':
        _min+=1
_min-=1

_max=0
while k>1:
    if k==2:
        _max+=1
        break
    elif k%4==0:
        _max+=k/2
        k/=4
    elif k%4==1:
        _max+=(k-2-3)/2+1
        k=(k-2-3)/4+1+1
    elif k%4==2:
        _max+=(k-2)/2
        k=(k-2)/4+1
    elif k%4==3:
        _max+=(k-3)/2+1
        k=(k-3)/4+1

print(_min)
print(int(_max))

(1)首先,不难发现无论是最多的情况还是最少的情况,都应当是完全二叉树。

(2)在前提(1)的情况下,红黑树上n个结点,就对应着有n+1个前端结点,这n+1个前端结点必定都是黑点。我们从n+1个前端结点开始向上演化。

(3)无论有多少个黑点,红黑树高度变化1后(保持高度一致),演化到的结果,都可以视为以下三种情况的组合:

(图像来源见水印,感谢!)

也就是说,两、三、四个黑结点如果要高度减一向上演化一层,其结果必定为这三种。

超过4个黑结点的情况可以看做几种case的组合。例如,5个前端结点就可以拆分为2+3的组合形式,再考虑2个黑点的情况。

特别的,如果只剩下两个黑点,我们就不需要再考虑高度减一的条件(无需和其他的黑点保持高度一致),可以自行决定这两个黑点的父结点的颜色。

由此可见,拆分的情况不是唯一的,而最多和最少的区别恰恰就在于拆分的方法!

不难发现:

case3,4个黑点产生了2个红点,产率1/2;

case2,3个黑点产生了1个红点,产率1/3;

case1,2个黑点产生了0个红点,产率0;

很显然,相同的黑点数目,求最小值,我们就要尽量使用case1,而求最大值就尽量使用case3!

看到这里,相信你就可以理解我的代码了。

求最小值就是尽量使用case1,演化一次,黑点数目折半。也就是不停地除以2,遇到奇数则拆解成2*n+3的形式。实际上就等同于(n+1的二进制表示中1出现的个数-1),你也可以用更加直观的方式去写。

求最大值则是尽量使用case3,也是不停的向上演化。当然,演化到只剩2个结点的时候,我们为了最大化,把根结点变成红色。


以上。转载请表明出处。

题目描述: 给定一些文件夹和文件,要求将它们按照层级关系输出成一个树形结构。 输入格式: 输入的第一行包含一个整数 n,表示文件夹和文件的个数。 接下来 n 行,每行包含一个字符串,表示一个文件夹或者文件。 其中,文件名和文件夹名都不包含空格和斜杠,文件名包含一个小数点,表示文件后缀。 输出格式: 输出一个树形结构,每行表示一个文件夹或者文件,按照层级关系缩进,文件夹名称后面要加上一个斜杠。 注意,最后一个文件夹或者文件名称后面不能有空格。 样例: 输入: 6 /root /etc /root/abcd.txt /root/bcd/ /etc/test/ /root/bcd/efg.txt 输出: /root /abcd.txt /bcd/ /efg.txt /etc /test/ 算法1 (模拟) $O(n)$ 思路: 本题需要我们输出文件夹和文件的层级结构,因此可以考虑使用哈希表记录每个文件夹和文件的层级结构。 对于每个文件夹和文件,我们可以通过判断其路径中"/"的数量来确定其所在的层级结构,具体来说,每个"/"表示一层。因此,我们可以将路径按"/"分开,然后统计"/"的数量,就可以得到该文件夹或文件所在的层级结构。 同时,由于本题要求输出树形结构,因此我们需要对每个文件夹和文件进行缩进处理,使其在输出时具有层级关系。具体来说,我们可以通过其所在的层级结构来确定输出时需要添加的缩进空格数量。 最后,我们可以按照文件夹和文件的层级结构从小到大的顺序进行输出,这样能够保证每个文件夹和文件的父节点已经被输出过了。 时间复杂度 哈希表的查询和插入操作都是常数级别的,因此总时间复杂度为 $O(n)$。 C++ 代码 算法2 (模拟) $O(nlogn)$ 思路: 本题可以使用字典树来实现,具体来说,我们可以将每个文件夹和文件的路径看作一个字符串,然后将所有字符串插入到字典树中。 同时,我们可以定义一个结构体,用来存储每个字符串的层级结构和缩进空格数量,具体来说,每个字符串的层级结构可以通过其在字典树中的深度来确定,而每个字符串的缩进空格数量则可以通过其所在的层级结构来确定。 最后,我们可以按照字符串的层级结构从小到大的顺序进行输出,这样能够保证每个字符串的父节点已经被输出过了。 时间复杂度 插入字符串的时间复杂度为 $O(nlogn)$,输出字符串的时间复杂度也为 $O(nlogn)$,因此总时间复杂度为 $O(nlogn)$。 C++ 代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值