题意:给一棵点带权(权值各不相同,都是小于10000的正整数)的二叉树的中序和后序遍历,找一个叶子使得它到跟的路径上的权和最小。如果有多解,该叶子本身的权应该尽量小。输入中每两行表示一棵树,其中第一行为中序遍历,第二行为后序遍历。
【分析】
后序遍历的第一个字符就是根,因此只需要在中序遍历中找到它,就知道左右子树的中序和后序遍历了。这样就可以先把二叉树构造出来,然后在执行一次递归遍历,找到最优解。
提示6-19:给定二叉树的中序遍历和后序遍历,可以构造出这棵二叉树。方法是根据后序遍历找到树根,然后在中序遍历中国找到树根,从而找出左右子树的结点列表,然后递归构造左右子树。
数组模拟:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
const int INF = 100000010;
int n, best, best_num, in_order[MAXN], post_order[MAXN];
int root, cnt;
struct Node
{
int Left, Right;
Node(): Left(0), Right(0) {}
}tree[MAXN];
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 u = post_order[R2];
int p = L1;
while (in_order[p] != u) p++;
int cnt = p - L1;//左子树结点个数
tree[u].Left = build(L1, p - 1, L2, L2 + cnt - 1);//左
tree[u].Right = build(p + 1, R1, L2 + cnt, R2 - 1);//右
return u;
}
void dfs(int u, int sum)
{
sum += u;
if (!tree[u].Left && !tree[u].Right)//叶子结点
{
if (best_num > sum || best_num == sum && best < u)
best = u, best_num = sum;
}
if (tree[u].Left) dfs(tree[u].Left, sum);
if (tree[u].Right) dfs(tree[u].Right, sum);
}
int main()
{
while(read_list(in_order) && read_list(post_order))
{
cnt = 1;
root = build(0, n-1, 0, n-1);
best_num = INF;
dfs(root, 0);
cout << best << "\n";
}
return 0;
}
/*
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
*/
动态创建:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
const int INF = 100000010;
int n, best, best_num, in_order[MAXN], post_order[MAXN];
struct Node
{
int v;
Node *Left, *Right;
Node(): v(0), Left(nullptr), Right(nullptr) {}
};
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;
}
Node* root;
//把in_order[L1..R1]和post_order[L2..R2]建成一棵二叉树,返回树根
Node* build(int L1, int R1, int L2, int R2)
{
if (L1 > R1) return nullptr;//空树
Node* u = new Node();
u->v = post_order[R2];
int p = L1;
while (in_order[p] != u->v) p++;
int cnt = p - L1;//左子树结点个数
u->Left = build(L1, p - 1, L2, L2 + cnt - 1);//左
u->Right = build(p + 1, R1, L2 + cnt, R2 - 1);//右
return u;
}
void dfs(Node* u, int sum)
{
sum += u->v;
if (u->Left == nullptr && u->Right == nullptr)//叶子结点
{
if (best_num > sum || best_num == sum && best < u->v)
best = u->v, best_num = sum;
}
if (u->Left != nullptr) dfs(u->Left, sum);
if (u->Right != nullptr) dfs(u->Right, sum);
}
void remove_tree(Node* u)
{
if (u == nullptr) return ;
remove_tree(u->Left);
remove_tree(u->Right);
delete u;
}
int main()
{
while(read_list(in_order) && read_list(post_order))
{
remove_tree(root);
root = build(0, n-1, 0, n-1);
best_num = INF;
dfs(root, 0);
cout << best << "\n";
}
return 0;
}
/*
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
*/