目录
1,题目描述
Sample Input 1:
9
7 8
- -
- -
- -
0 1
2 3
4 5
- -
- -
Sample Output 1:
YES 8
Sample Input 2:
8
- -
4 5
0 6
- -
2 3
- 7
- -
- -
Sample Output 2:
NO 1
题目大意
判断一棵树是否为完全二叉树(允许最后一层有空节点,且最后一层的节点需要按照自左向右的顺序排列),是则输出最后一个节点的index,不是则输出根节点的index;
2,思路
借鉴了这位大佬的思路!@程勇uestc【PAT甲级1110 Complete Binary Tree (25 分)题解】
数据结构
- struct node{
int left, right;
}tree[25]树的存储方式; - bool notRoot[N]:判断节点i是否为根节点,false是、true否;
算法
- 接收数据构建树,并判断哪些节点不是根节点:
- 确定根节点:
- DFS遍历树,并记录树可达的最远距离maxDep和最远节点lastNode(利用二叉树数组表示的特性,假设下标从1开始:根节点i,其孩子在数组中的位置分别为:左孩子2*i,右孩子2*i+1。这里不真实声明数组,而只是记录数组的最大长度,即最后一个节点)
- (下标从1开始)若最后一个节点位置为N,即说明为完全二叉树:
3,AC代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int left, right;
}tree[25];
int N, root, lastNode, maxDep = 0;
void dfs(int start, int dep){
if(start == -1)
return;
if(dep > maxDep){ //寻找最远的一个节点
maxDep = dep;
lastNode = start;
}
dfs(tree[start].left, 2 * dep);
dfs(tree[start].right, 2 * dep + 1);
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
cin>>N;
bool notRoot[N], flag = false;
string s1, s2;
node n;
fill(notRoot, notRoot + N, false); // !!!注意初始化
for(int i = 0; i < N; i++){ //节点编号从0开始
cin>>s1>>s2;
n.left = (s1 == "-" ? -1 : stoi(s1));
n.right = (s2 == "-" ? -1 : stoi(s2));
if(n.left != -1) notRoot[n.left] = true;
if(n.right != -1) notRoot[n.right] = true;
tree[i] = n;
}
for(int i = 0; i < N; i++){ //确定根节点
if(notRoot[i] == false){
root = i;
break;
}
}
dfs(root, 1);
if(maxDep == N) //最远距离等于节点个数
flag = true;
if(flag)
printf("YES %d", lastNode);
else
printf("NO %d", root);
return 0;
}
4,解题过程
第一搏
DFS+完全二叉数组
#include<bits/stdc++.h>
using namespace std;
struct node{
int left, right;
}tree[25];
int N, root, lastNode;
int binTree[1000];//数组记录完全二叉树
void dfs(int start, int dep){
if(start == -1)
return;
binTree[dep] = start;
dfs(tree[start].left, 2 * dep + 1);
dfs(tree[start].right, 2 * dep + 2);
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &N);
bool notRoot[N], flag = true;
char c1, c2;
node n;
for(int i = 0; i < N; i++){//节点编号从0开始
cin>>c1>>c2;
n.left = (c1 == '-' ? -1 : c1-'0');
n.right = (c2 == '-' ? -1 : c2-'0');
if(n.left != -1) notRoot[n.left] = true;
if(n.right != -1) notRoot[n.right] = true;
tree[i] = n;
}
for(int i = 0; i < N; i++)//寻找根节点
if(!notRoot[i]){
root = i;
break;
}
fill(binTree, binTree + 1000, -1);
dfs(root, 0);
lastNode = binTree[N-1];//最后一个节点
for(int i = 0; i < N; i++){
if(binTree[i] == -1)
flag = false;
}
if(flag)
printf("YES %d", lastNode);
else
printf("NO %d", root);
return 0;
}
第二搏
突然发现,节点编号并不一定是单个字符,于是:
第三搏
???应该没问题了呀
我又把程序来来回回看了无数遍,又去翻阅其他大佬的博客,又辗转回来继续研究,然而还是没问题(虽然我的代码逻辑有点复杂,【看到一位大佬的解法和我类似,但更加简洁】,但理论上说应该完全可行的呀)
几经周折之后,我锁定了一个位置:
(若i不是根节点,则notRoot[i]=true;)
在我最开始的代码里没有将此数组全部初始化为false(因为我以为默认值就是0.。。。所以就没管它),但确实没有别的地方可改了,于是决定搏一搏(接收数据之前先初始化),
于是单车变摩托o(* ̄▽ ̄*)ブ:
#include<bits/stdc++.h>
using namespace std;
struct node{
int left, right;
}tree[25];
int N, root, lastNode;
int binTree[10000];//数组记录完全二叉树
void dfs(int start, int dep){
if(start == -1)
return;
binTree[dep] = start;
dfs(tree[start].left, 2 * dep + 1);
dfs(tree[start].right, 2 * dep + 2);
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &N);
bool notRoot[N], flag = true; //若i不是根节点,则notRoot[i]=true
string s1, s2;
node n;
fill(notRoot, notRoot + N, false); // !!!
for(int i = 0; i < N; i++){ //节点编号从0开始
cin>>s1>>s2;
n.left = (s1 == "-" ? -1 : stoi(s1));
n.right = (s2 == "-" ? -1 : stoi(s2));
if(n.left != -1) notRoot[n.left] = true;
if(n.right != -1) notRoot[n.right] = true;
tree[i] = n;
}
for(int i = 0; i < N; i++) //寻找根节点
if(!notRoot[i]){
root = i;
break;
}
fill(binTree, binTree + 10000, -1);
dfs(root, 0);
lastNode = binTree[N-1];//最后一个节点
for(int i = 0; i < N; i++){
if(binTree[i] == -1){
flag = false;
break;
}
}
if(flag)
printf("YES %d", lastNode);
else
printf("NO %d", root);
return 0;
}
第四搏
欣赏了和我解法类似的大神思路,发现可以进一步简化,比如不需要BinTree数组,只需要DFS时记录最远的位置maxDep即可,若maxDep==N,说明为完全二叉树(具体见思路)。