L2-051 满树的遍历 - 团体程序设计天梯赛-练习集 (pintia.cn)
题解
- 数据结构选择
为了表示树的结构,我们可以使用邻接表。邻接表是一种常用的图和树的表示方法,它能够高效地存储每个节点的子节点信息。在本题中,我们可以使用一个数组 g
,其中 g[i]
存储节点 i
的所有子节点。同时,使用一个数组 pre
来存储前序遍历的结果。
- 输入处理
-
首先读取树中结点的个数
n
。 -
接着,依次读取每个结点的父结点编号。对于每个结点
i
,如果其父结点编号为 0,则说明该结点是根结点,记录其编号;否则,将结点i
添加到其父结点的子节点列表中。
- 计算树的度和判断是否为 k 阶满树
-
我们可以通过深度优先搜索(DFS)来遍历树。在遍历过程中,我们需要记录每个非叶结点的度,并找出树的最大度
k
。 -
初始化
k
为根结点的度。在 DFS 过程中,如果遇到某个非叶结点的度不等于k
,则说明该树不是 k 阶满树,将标记flag
设为false
。同时,更新k
为所有非叶结点度的最大值。
- 前序遍历
- 前序遍历的顺序是:根节点 -> 左子树 -> 右子树。在 DFS 过程中,当访问到一个节点时,将其加入到
pre
数组中,然后递归地访问其所有子节点。由于题目要求兄弟结点按编号升序访问,我们在存储子节点时会自动满足这个条件。
- 输出结果
-
首先输出树的度
k
。 -
根据
flag
的值,输出yes
或no
表示该树是否为 k 阶满树。 -
最后输出前序遍历序列
pre
,数字间以一个空格分隔,行首尾不得有多余空格。
代码
cpp
#include<bits/stdc++.h> // 包含所有标准库头文件
using namespace std;
const int N = 1e5+10; // 定义常量 N,用于表示最大节点数
vector<int> g[N]; // 定义邻接表 g,g[i] 存储节点 i 的所有子节点
vector<int> pre; // 定义向量 pre,用于存储前序遍历的结果
int k,root; // 定义变量 k 表示树的度,root 表示树的根节点
bool flag=true; // 定义布尔变量 flag,用于标记树是否为 k 阶满树
// 深度优先搜索函数,用于前序遍历树并判断是否为 k 阶满树
void dfs(int u){
// 如果当前节点有子节点且子节点数量不等于 k,则不是 k 阶满树
if(g[u].size()>0 && g[u].size()!=k){
flag=false;
// 更新树的度 k 为当前节点子节点数量和 k 中的较大值
k=max(k,(int)g[u].size());
}
// 将当前节点加入前序遍历结果
pre.push_back(u);
// 递归遍历当前节点的所有子节点
for(int i=0; i<g[u].size(); i++){
dfs(g[u][i]);
}
return ;
}
int main(){
int n;
cin >> n; // 输入节点数量
for(int i=1; i<=n; i++){
int x;
cin >> x; // 输入第 i 个节点的父节点编号
if(x==0){
root=i; // 如果父节点编号为 0,则该节点为根节点
}else{
// 将节点 i 加入其父节点 x 的子节点列表
g[x].push_back(i);
}
}
// 初始化树的度 k 为根节点的子节点数量
k=g[root].size();
// 从根节点开始进行深度优先搜索
dfs(root);
// 输出树的度
cout << k;
// 根据 flag 的值输出是否为 k 阶满树
if (flag)cout << " yes";
else cout << " no";
cout << endl;
// 输出前序遍历结果
for (int i = 0; i < pre.size(); i++) {
if (i)cout << " ";
cout << pre[i];
}
}