习题6-11 树重建 UVa10410

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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值