1.题目描述:点击打开链接
2.解题思路:由于只给定了BFS,DFS序列,当然要通过先序遍历(即DFS)和层次遍历(即BFS)将原树构造出来。先序遍历时利用BFS数组找出正在访问的结点的子结点,层次遍历时利用DFS数组找到本层结点的结束位置(即下一层的起始结点),由于细节比较多,详细过程请参见程序的注释
3.代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 1000 + 10;
int n;
int node[maxn][maxn];
int dfs[maxn], bfs[maxn];
int vis[maxn];
int error[maxn]; //记录非法的数
map<int, int>pos;//记录每个数在dfs数组中的下标
map<int, int>po; //记录每个数在bfs数组中的下标
queue<int>q,r;
int get_next(int pos)
{
for (int i = pos + 1; i < n; i++)
if (vis[po[dfs[i]]] == 1)return i;
return n;
}
void solve(int start,int end)
{
if (n == 1)return;
if (n == 2)node[dfs[0]][dfs[1]] = 1;
else if (n>=3)
{
if (end - start<2){ error[dfs[start]] = 1; return; }
int j =1;
int p = start + 1;
while (vis[j] == 1)j++;//找bfs数组的起始点
while (dfs[p] != bfs[j])p++;//找dfs数组的起始点
int common = j;
int d = 0;
if (p == n - 1 && end < p){ error[dfs[start]] = 1; return; }//非法情况
for (; d < min(n - j, n - p); d++)
if (dfs[p + d] != bfs[j + d]){ j += d; break; }//找两个队列的分裂点
int k = j;
for (; k < n;k++)
if (dfs[p+d] == bfs[k])break;//寻找两个队列的重合点
for (int l = common; l < k; l++)//将前一个重合点和当前重合点之间的数放入队列(第一个位置默认是1)
{
q.push(bfs[l]);
r.push(bfs[l]);
}
int ok = 0;
while (!q.empty())//根据dfs队列来判断这些数是谁的子结点
{
int v = q.front(); q.pop();
if (pos[v]>start&&pos[v] < end)
{
ok = 1;
node[dfs[start]][v] = 1;
vis[po[v]] = 1;//把入过队列且恰好在区间内的子结点标记
}
}
if (!ok){ error[dfs[start]] = 1; return; }//没有找到任何子结点
while (!r.empty())
{
int v = r.front(); r.pop();
if(!error[v])solve(pos[v], get_next(pos[v]));//添加剪枝,减少没必要的递归
}
}
}
int main()
{
while (scanf("%d", &n)==1&&n)
{
pos.clear();
po.clear();
memset(node, 0, sizeof(node));
memset(dfs, 0, sizeof(dfs));
memset(bfs, 0, sizeof(bfs));
memset(error, 0, sizeof(error));
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; i++)
{
scanf("%d", bfs + i);
po[bfs[i]] = i;
}
for (int i = 0; i < n; i++)
{
scanf("%d", dfs + i);
pos[dfs[i]] = i;
}
solve(0,n);
for (int i = 1; i <= n; i++)
{
printf("%d:",i);
for (int j = 1; j <= n; j++)
if (node[i][j]) printf(" %d", j);
printf("\n");
}
}
return 0;
}