UVa 548 Tree(中序遍历+后序遍历)

给一棵点带权(权值各不相同,都是小于10000的正整数)的二叉树的中序和后序遍历,找一个叶子使得它到根的路径上的权和最小。如果有多解,该叶子本身的权应尽量小。输入中每两行表示一棵树,其中第一行为中序遍历,第二行为后序遍历。


样例输入:
3 2 1 4 5 7 6
3 1 2 5 6 7 4
7 8 11 3 5 16 12 18
8 3 11 7 16 18 12 5
255
255
样例输出:
1
3
255

知识点:由中序遍历和后序遍历构建二叉树(中序遍历加上其余两种遍历中任意一种,都可以还原二叉树),因为后序遍历的最后一个字符就是根(前序遍历的第一个字符是根),然后再到中序遍历中找到根,就可以知道其左右子树的中序和后序遍历,然后递归,代码如下:

#include <bits/stdc++.h>
using namespace std;
#define fast                                ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define ll                                  long long
#define _for(i,a,b)                         for(int i = a;i < b;i++)
#define rep(i,a,b)                          for(int i = a;i <= b;i++)
#define all(s)                              s.begin(), s.end()

const int maxn = 1e9;
const int maxv = 10000 + 10;
int in_order[maxv], post_order[maxv], lch[maxv], rch[maxv];
int n;

bool read_list(int* a)//读取中序遍历和后序遍历
{
	string line;
	if (!getline(cin, line)) return false;
	stringstream ss(line);
	n = 0;
	int x;
	while (ss >> x)a[n++] = x;
	return n > 0;
}

//in_order[l1..r1]和post_order[l2..r2]建成二叉树,返回树根
int build(int l1, int r1, int l2, int r2)
{
	if (l1 > r1) return 0;//空树
	int root = post_order[r2];//后序遍历最后一个结点为根
	int p = l1;
	while (in_order[p] != root)p++;//在中序遍历中找到根
	int cnt = p - l1;//左子树的结点个数
	lch[root] = build(l1, p - 1, l2, l2 + cnt - 1);//构建左子树
	rch[root] = build(p + 1, r1, l2 + cnt, r2 - 1);//构建右子树
	return root;
}

int best, bestsum;//目前为止的最优解和对应的权和

void dfs(int u, int sum)
{
	sum += u;
	if (!lch[u] && !rch[u]) //叶子(无左子树和右子树)
	{
		if (sum < bestsum || (sum == bestsum && u < best))
		{
			best = u;
			bestsum = sum;
		}
	}
	if (lch[u])dfs(lch[u], sum);
	if (rch[u])dfs(rch[u], sum);
}

int main()
{
	while (read_list(in_order))
	{
		read_list(post_order);
		build(0, n - 1, 0, n - 1);
		bestsum = maxn;
		dfs(post_order[n - 1], 0);
		printf("%d
", best);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/theory/p/11884333.html