题目链接:0, 1, 2, Tree!
本道题目其实就是一道贪心的题目,对于思维的考察较多。
思路:
1.首先我们想想什么情况下该树不存在?
由二叉树的性质可知每一个子节点个数为2的树都必须有两个,每一个子节点为1的树必须有1个,那么最后的0,也就是叶子节点的数量跟这两个有什么关系?
先看一棵树:
O
/ \
aO Oe 假设这么一棵树,我们可以发现a的子节点有两个,那么叶子节点就比
/ \ | 这个节点多了1,子节点为1的则就只有一个,我们可以把d这个叶子节点
O O O 分给根节点,这样每个子节点个数为2的节点都有2个叶子节点。
b c d 所以可以知道,当叶子节点个数 = 子节点个数为2的节点个数 + 1
2.怎么贪心的去考虑这棵树?
换种问法,如何合理分配这三种节点,首先0肯定是叶子节点,所以不用考虑,那就考虑如何分配这两种节点使树的高度最小?
O O
/ \ |
O O O
/ \ / \ / \
O O O O O O
/ \ | | / \ / \
O O O O O O O O
|
O
从这两棵树中我们可以清晰的发现,要使得高度最小,那肯定是先放子节点个数为2的再去放1的。
那么思路到这边就结束了。
代码如何实现?以及一些细节:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a,b,c;void solve(){cin>>a>>b>>c;if(a+1!=c){cout<<-1<<"\n";return;}int h1=0;for(int i=1;i<=a;i++){if(pow(2,i)-1>a){h1=i-1;break;}}//cout<<"h1="<<h1<<"\n";int less=a-(pow(2,h1)-1);//还有多少个2//cout<<"less="<<less<<"\n";int cur_less=(pow(2,h1)-less);//目前该行还有多少个1可以填//cout<<"cur="<<cur_less<<"\n";int p=pow(2,h1)+less;//表示接下来还有多少点//cout<<"p="<<p<<"\n";if(!less&&!b){//如果是满二叉树cout<<h1<<"\n";return;}if(cur_less>=b){h1++;cout<<h1<<"\n";}else{b-=cur_less;h1++;h1+=((b-1)/p+1);cout<<h1<<"\n";}}signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int t;cin>>t;while(t--){solve();}return 0;
}