Problem.png
給出一棵樹的中序和后序遍歷,問從根到哪個葉結(jié)點的權(quán)值累加和最大。
已知二叉樹的中序和后序,可以構(gòu)造出這棵二叉樹,然后遞歸深搜這棵樹,比較每條路徑的累加權(quán)值即可。
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
const int maxv = 10000 + 10;
int in_order[maxv], post_order[maxv], lch[maxv] = {0}, rch[maxv] = {0};
int n;
bool read_list(int* a) {
string line;
if (!getline(cin, line)) return false;
stringstream ss(line);
int val;
n = 0;
while (ss >> val) {
a[n] = val;
n++;
}
return true;
}
/**
* in_order[L1...R1]是當(dāng)前這棵樹的中序
* post_order[L2...R2]是當(dāng)前這棵樹的后序
* 算法的主題思想是通過后序的最后一個值找到當(dāng)前這棵樹的根
* 然后在中序中找到根的位置,則左側(cè)為左子樹的中序,右側(cè)為右子樹的中序
* 再根據(jù)左子樹的結(jié)點個數(shù)找出左子樹的后序和右子樹的后序
* 之后再分別對左子樹和右子樹進(jìn)行遞歸,得到當(dāng)前根的左孩子和右孩子,完成建樹
**/
int build(int L1, int R1, int L2, int R2) {
if (L1 > R1) return 0; // 遞歸到空樹時結(jié)束遞歸
int root = post_order[R2];
int p = L1;
while (in_order[p] != root) {
p++;
}
int lcnt = p - L1; // 左子樹的結(jié)點個數(shù)
// lpost L2, L2 + lcnt - 1
// rpost L2 + lcnt, R2 - 1
lch[root] = build(L1, p - 1, L2, L2 + lcnt - 1);
rch[root] = build(p + 1, R1, L2 + lcnt, R2 - 1);
return root;
}
int best, best_sum;
// 深度優(yōu)先搜索,不斷累加權(quán)值
// 因為是遞歸,所以權(quán)值要作為參數(shù)
void dfs(int u, int sum) {
sum += u;
if (!lch[u] && !rch[u]) {
if (sum < best_sum || (sum == best_sum && u < best)) {
best = u;
best_sum = 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);
int root;
root = build(0, n - 1, 0, n - 1);
best_sum = 10000000;
dfs(root, 0);
cout << best << endl;
}
return 0;
}