非常经典也比较有意思的一题, 由树的层序遍历和前序遍历构造树.
但是我们都知道, 没有中序的话构造出来的树的可能情况是很多的,
因此题目加了一个很关键的限制条件, 就是遍历序列都是先从点数小的子节点开始访问的.
一开始没注意到这个关键, 空想了很久也没想出来比较好的方法.
其实思路和其他同类的问题(根据两个遍历序列构造树)的思路完全一样, 都是以一个序列为标准, 对另一个序列不断分解成几段, 每一段就是一棵子树中的所有结点.
思路 : 比如像这道题按层序和前序构造树, 可以看到如果在层序序列中同一层中选定相邻两个节点, 那么在先序序列中这两个节点之间的子序列, 就是选定的第一个节点的子树的所有结点. 按这种想法递归进行, 就能划分出一棵棵子树了. 另一个难点在于如何判断层序序列中同一层的结点, 观察之后不难发现, 如果A, B是同一层的结点, 那么在先序序列中B必定排在A之后, 以此类推.
把思路弄清楚就可以开始写代码划分子树了. 还是要注意必须是由小的子节点开始遍历的.
AC代码如下 :
(因为题目中没说是二叉树, 就写了一个可以判断多叉树的, 但写得不是很美观, 所以乍一看可能有点费解..)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <list>
#include <cassert>
#include <iomanip>
//#pragma warning(disable:4996) //关掉4996警告
/*
Uva 10410 Tree Reconstruction
关键 : Note that when a parent was expanded the children were traversed
in ascending order. 就是说遍历子节点不是随便遍历的, 必须按由小到大的顺序遍历
*/
using namespace std;
int N;
struct Node {
int left, right;
int parent;
Node (int _a, int _b, int _c) : left (_a), right (_b), parent (_c) { }
};
map<int, vector<int> > Childs;
vector<int> PreOrder;
queue<int> LevelOrder;
void solve ( ) {
queue<Node> Q;
LevelOrder.pop ( );
Q.push (Node(1, N-1, PreOrder[0]));
while ( !Q.empty ( ) ) {
int left = Q.front ( ).left, right = Q.front ( ).right, parent = Q.front ( ).parent; Q.pop ( );
if ( left > right ) continue;
Childs[parent].push_back (PreOrder[left]);
LevelOrder.pop ( );
for ( int i = left+1; i <= right; i++ ) { // only if left < right
int next = LevelOrder.front ( );
if ( PreOrder[i] == next && PreOrder[left] < PreOrder[i] ) { // Because traverse childs in ascending order
Q.push (Node (left + 1, i - 1, PreOrder[left]));
Childs[parent].push_back (PreOrder[i]);
LevelOrder.pop ( );
left = i;
}
}
if ( left < right ) Q.push (Node (left+1, right, PreOrder[left]));
}
}
int main( ) {;
while ( cin >> N ) {
Childs.clear ( );
PreOrder.clear ( );
while ( !LevelOrder.empty() ) {
LevelOrder.pop ( );
}
for ( int i = 0, tmp; i < N; i++ ) {
cin >> tmp;
LevelOrder.push (tmp);
}
for ( int i = 0, tmp; i < N; i++ ) {
cin >> tmp;
PreOrder.push_back (tmp);
}
solve ( );
for ( int j = 1; j <= N; j++ ) {
cout << j << ":";
for ( int i = 0; i < Childs[j].size ( ); i++ ) {
cout << " " << Childs[j][i];
}
cout << endl;
}
}
//system ("pause");
return 0;
}