16. 二叉哥的二叉树
·
1 问题描述
题目描述
传说计算机学院有一位前辈叫做二叉哥,他十八般算法样样精通。他当年在程设的时候由于二叉树一举成名。大家为了纪念这一事件,尊称他为二叉哥!二叉树是一个什么样的东西呢?现在我们就来揭开二叉哥的二叉树的神秘面纱吧!
下图就是一棵有着9个节点的二叉树。顾名思义,二叉树就像一棵倒着生长的树,每个分叉点可以分出去两个枝条。我们把分叉点叫做"节点”,因为每个分叉点最多可以分出去两个枝条,所以就叫做"二叉”树。最顶层只有一个节点,我们把它叫做根节点。下图中,标号为1的节点就是根节点,它有两个孩子:节点2和节点3。节点2只有一个孩子,标号为4,而节点3有两个孩子,标号分别为5和6。下图中的二叉树第3层有3个节点,分别是7、8和9号节点。

二叉哥对于二叉树的掌握已经到了出神入化的程度,为了维护他的二叉树霸主地位,他准备了2^2^2^2^2个问题来迎接挑战者,现在我们来看下第0道吧。
一个有n个节点的二叉树的第m层至多有多少个节点?
输入
输入的第一行为一个数字T(1 <= T <= 10000),表示有T组数据。
接下来的T行每行有两个数字n和m(0 <= n, m <= 10^8),表示二叉树有n个节点,求m层最多有多少个节点。
根节点所在的为第0层。
输出
每个用例输出一个数字,表示最多的节点个数。
2 解题
- 这个题我其实想了很久,因为刚开始的时候我一直没有思路,觉得有太多的情况需要考虑,尤其是当第m层放不满的时候,如果要从右边拿过来的话就像是我们平时所说的牵一发而动全身,实在头疼
- 最后终于发现了其中的规律
- 首先从最简单的情况入手,先是每一层只放一个,然后来补嘛,

然后开始往右填每一层,这个层已经不是横着的层了,但是其中还是有相同的规律

当第4层无法填满的时候,把第四层当做一个新的开始,是不是自然而然想到递归了
因为它回到了最开始的情况,情形处理都是一样的,不过这个时候传进去的参数m就不等于一开始的m了,应该是2

递归结束的条件在程序里面都有写
- 代码:
#include <math.h>
#include<stdio.h>
#include<iostream>
#include<cstdlib>
using namespace std;
int num=0;
void count(int n,int m){
if(n<m+1){ //只放一个都不够
num+=0;
return;
}
else if(n==m+1){ //只放一个刚刚好
num+=1;
return ;
}
else{
n=n-m-1; //每层放一个之后剩下的
num += 1; ///每层放一个那么m层就有1个了哦
int layer=1; //第0层已经有了,直接开始第1层吧
if(n==0||layer>m) //没有节点了,或者层数已经够了,结束递归
return;
int need;
need=pow(2,layer)-1; //放满需要的节点数
while(n-need>0){ //只要能放满还剩,重复一直放
num+=pow(2,layer-1);
layer++;
n-=need;
need=pow(2,layer)-1;
if(layer>m) //注意判断是否达到了退出的条件
return ;
}
if(n-need==0){ //刚好放满
num+=pow(2,layer-1);
return;
}
else //新的一层不够放,那么当做一个新的情况开始递归吧
count(n,layer-1);
}
}
int main() {
int n,m,t;
//freopen("file in.txt","r",stdin);
cin>>t;
while(t--){
cin>>n>>m;
num=0; //每一次都要初始化,不然会累加
count(n,m);
cout<<num<<endl;
}
return 0;
}
3 小结
- 二叉树一般都有很强的规律性,只要能寻找到其中的规律,那么就可以使用递归,因为没有规律的话递归是没有办法连贯下去的

更多推荐
所有评论(0)