此题感慨良多。
首先,我看到这个题我是觉得题意简单好懂,但是恰恰最开始就把我搞糊涂了。
输入:第一行 节点数n、第二行 bfs序列,第三行 dfs序列。
输出:输出最初看不懂,原题是真的读不懂= =|||。看了好几遍书上的题目,才注意到输出的是编号n的子节点,例如 编号4有子节点3、5 那么 4: 3 5。
题意还容易误解,在此强调,以免后来者和我犯一样的错误。
误解1:这棵树是一个二叉树(从来没说过,不要先入为主)。
误解2:树的节点是先访问先输出(bfs和dfs序和我们要输出的答案都是升序的)(不要漏看题意)。
我刚开始想的是和先序和中序一样,一个个确定根节点递归实现,后来不管怎么想都觉得难以实现。
最后确实是苦读博客(感谢大佬QAQ)才勉强写完。
我们可以发现以下几件事情
1.bfs序列中相邻的u和v可能是兄弟节点,dfs序列中相邻的u和v可能是父子节点。
2.因为一个节点按升序展开,所以兄弟节点u和v,u<v,在bfs节点中,就会有u和v相邻,且输入是v紧跟u,以及u<v。
3.我们现在知道了2这件事情,那么如果bfs序列中有一个v紧跟u,但是u>v,这意味着什么?这意味着v不是u的兄弟节点,所以v是一个子节点,是u的第一个兄弟节点的子节点。
4.dfs序列中,相邻的u和v可能是父子节点,所以如果有u和v满足3而且在dfs序列中相邻,那么v是u的子节点。
5.如果两个节点u和v是兄弟节点那么在bfs序中一定是相邻的。
了解了以上情况,我们可以的到可以判断子节点的几个条件
1.bfs序中节点u,紧跟节点u的v,u>v
2.dfs序中节点u,紧跟节点u的v,在bfs序中不相邻
所以现在我们的问题变成了如何边确认dfs序列相邻又要确认在bfs中是否相邻。暴力点,每次判断都遍历一遍,n最大为1000好像是可以……但是也麻烦。
我看的大佬的方法是借助栈,用栈保存dfs序列,然后用一个数组保存bfs的距离,即u和v相邻,且v紧跟u,那么pos[u]=pos[v]+1。
不过为什么用栈呢,我也不懂,我猜是因为dfs是栈实现的(瞎猜的没有任何依据的)。
那么,现在我们就可以挨个遍历dfs,上一个节点是stack的top,也就是u,现在遍历到的点是t,u和t在dfs序列中相邻,且t到u后边。
所以以下条件就可以直接判断为u是t的父节点
1.pos[u]+1==pos[t] && u>t
2.pos[u]+1<pos[t]
3.root==u
我的理解也就到此为止了,感觉还有很多细节没有很明白,以后再看吧……
#include <iostream>
#include <cstring>
#include <vector>
#include <stack>
using namespace std;
const int maxn = 1005;
int pos[maxn];
vector<int> G[maxn];
stack<int>s;
int main()
{
int n;
while (cin >> n)
{
int t;
for (int i = 1; i <= n; i++)
{
scanf("%d", &t);
pos[t] = i;
G[i].clear();
}
int root;
scanf("%d", &root);
s.push(root);
for (int i = 1; i < n; i++)
{
scanf("%d", &t);
for (;;)
{
int u = s.top();
if ((pos[u] + 1 == pos[t] && u > t) || pos[u] + 1 < pos[t] || u == root)
{
G[u].push_back(t);
s.push(t);
break;
}
else
s.pop();
}
}
for (int i = 1; i <= n; i++)
{
printf("%d:",i);
for (int j = 0; j < G[i].size(); j++)
{
printf(" %d", G[i][j]);
}
cout << endl;
}
}
return 0;
}