一、题意
第一行一个n表示一棵树有n个结点。
然后第二三行分别给出这棵树的bfs和dfs序列。(子节点中会先遍历编号小的)
要求输出每个节点的子节点有哪些。
二、解析
这题比较难。最终做法是,使用栈来模拟dfs的过程。在输入dfs序列时,同时维护一个栈,当在树上递归时则往栈中加入该节点,当发生了回溯时,则需要从栈中排出结点。bfs序列实际上我们可以从中提取出结点的pos数组(即结点在层次遍历中的下标)。利用这个pos数组,在dfs发生递归时,除了第一层外,当前结点的pos应该大于上一结点的pos+1(这样才会是往下走的dfs,并且不是兄弟结点);当发生回溯时,当前节点的pos应该小于等于上一结点的pos+1(这样才说明dfs已经遍历完一棵子树,所以结点pos往回跳了,所以才变小了,相等时表示是兄弟节点)。利用这一特点,在递归发生时,当前节点和上一结点就是父子关系,记录到ans中即可。
三、代码
#include <iostream> #include <stack> #include <vector> using namespace std; const int maxn = 1000 + 5; int n, pos[maxn]; vector<int> ans[maxn]; int main() { while(cin >> n) { for(int i = 1; i <= n; i ++) ans[i].clear(); for(int i = 0, x; i < n; i ++) { cin >> x; pos[x] = i; } stack<int> stk; for(int i = 0, x; i < n; i ++) { cin >> x; while(!stk.empty() && i >= 2 && pos[x] <= pos[stk.top()] + 1) stk.pop(); if(!stk.empty()) ans[stk.top()].push_back(x); stk.push(x); } for(int i = 1; i <= n; i ++) { cout << i << ":"; for(int child : ans[i]) cout << " " << child; cout << endl; } } }
四、归纳
- 难题的话还是要靠多刷题积累经验了