题目分析
问题描述
本题要求根据给定的 BFS(广度优先搜索)和 DFS(深度优先搜索)遍历序列,重建一棵树的结构。这棵树有 nnn 个节点,编号从 111 到 nnn,并且题目特别说明:当父节点扩展子节点时,子节点是按编号升序遍历的。这意味着在 BFS 和 DFS 遍历中,同一个父节点的子节点顺序是一致的。
输入输出格式
- 输入:第一行是节点数 nnn (1≤n≤1000)(1 \leq n \leq 1000)(1≤n≤1000),接下来一行是 BFS 序列,再接下来一行是 DFS 序列。
- 输出:输出 nnn 行,每行格式为
节点: 子节点1 子节点2 ...,子节点按升序排列。
关键观察
- BFS 序列反映了树的层级结构,根节点是第一个元素。
- DFS 序列反映了深度优先的访问顺序,可以用于确定父子关系。
- 由于子节点按升序遍历,在 DFS 序列中,一个节点的子节点会连续出现,直到遇到该节点的兄弟节点或更高层级的节点。
算法思路
我们可以利用栈来模拟 DFS 过程,同时借助 BFS 序列中的位置信息来确定父子关系。具体来说:
- 用
pos数组记录每个节点在 BFS 序列中的位置(索引从 111 开始)。 - 将 DFS 序列的第一个节点(根节点)压入栈。
- 遍历 DFS 序列的剩余节点:
- 不断检查栈顶节点
u:- 如果
u是根节点 或者pos[u] + 1 < pos[x](其中x是当前 DFS 节点),说明x是u的子节点。- 将
x加入u的子节点列表 - 将
x压入栈(因为x可能是后续节点的父节点) - 结束循环
- 将
- 否则,弹出栈顶(说明
u没有更多子节点)
- 如果
- 不断检查栈顶节点
关键条件 pos[u] + 1 < pos[x] 的解释:
pos[u] + 1表示在 BFS 中u的下一个位置- 如果
pos[x]仅比pos[u]大 111,则x可能是u的兄弟节点 - 如果
pos[x]大于pos[u] + 1,说明x在 BFS 中位于u的"后面足够远",因此x是u的子节点
复杂度分析
- 时间复杂度:O(nlogn)O(n \log n)O(nlogn),主要来自最后的子节点排序
- 空间复杂度:O(n)O(n)O(n),用于存储栈、位置数组和子节点列表
代码实现
// Tree Reconstruction
// UVa ID: 10410
// Verdict: Accepted
// Submission Date: 2025-10-16
// UVa Run Time: 0.000s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
int main() {
int n;
while (cin >> n) {
vector<int> pos(n + 1); // 记录每个节点在BFS中的位置
vector<vector<int>> children(n + 1); // 存储每个节点的子节点列表
// 读取BFS序列并记录位置
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
pos[x] = i;
}
// 读取DFS序列
vector<int> dfs(n);
for (int i = 0; i < n; i++) {
cin >> dfs[i];
}
int root = dfs[0]; // DFS第一个节点是根节点
stack<int> st;
st.push(root);
// 处理DFS序列的剩余节点
for (int i = 1; i < n; i++) {
int x = dfs[i]; // 当前处理的节点
while (true) {
int u = st.top(); // 栈顶节点
// 关键判断:如果u是根节点,或者x在BFS中的位置足够靠后
if (u == root || pos[u] + 1 < pos[x]) {
children[u].push_back(x); // x是u的子节点
st.push(x); // 将x压入栈,因为它可能是后续节点的父节点
break;
} else {
st.pop(); // u没有更多子节点,弹出
}
}
}
// 输出结果
for (int i = 1; i <= n; i++) {
cout << i << ":";
// 对子节点排序以满足题目要求的升序输出
sort(children[i].begin(), children[i].end());
for (int child : children[i]) {
cout << " " << child;
}
cout << endl;
}
}
return 0;
}
该算法巧妙地利用了 BFS 和 DFS 序列的特性,通过栈来维护当前可能的父节点链,能够高效地重建树结构。条件 pos[u] + 1 < pos[x] 是算法的核心,它确保了正确的父子关系判断。
454

被折叠的 条评论
为什么被折叠?



