简单描述下原题意,题目给出二叉树按照中序遍历和后序遍历得到的序列, 需要求出从根节点到叶子节点最短路径的叶子的权重。(其实也是它的编号)。如果存在多个解,则选择权重最小的那个。
解题思路: 1.需要解决一个问题:如何根据二叉树的中序遍历和后序遍历还原二叉树。 方法挺简单的,根据它们的各自定义可知,后序遍历中的最后一个数就是根节点值。然后在中序遍历中找到此值,它的左边为左子树,右边为右子树。然后递归求解。 同样的 如果知道二叉树的前序遍历和中序遍历又该如何还原二叉树呢?(中序遍历必须已知,否则二叉树不唯一。想想为什么?)。相仿,先序遍历中第一个值就是根节点。还原二叉树方法同上。
2. 如何求解权重和最小路径。这个只需要进行一次先序遍历,求出根节点到叶子节点所有的解。然后与最优解进行比较即可以得到。
ac代码如下:
#include <iostream>
#include <sstream>
using namespace std;
const int MAXN = 100000;
int in_order[MAXN], post_order[MAXN], lef[MAXN], righ[MAXN];
int NCNT =0; // 存放输入的数据的个数
// 返回根节点
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 rCnt = r1 - p;// 计算右子树的个数
int lCnt = p - l1; // 左子树个数
lef[root] = build(l1, l1+lCnt-1, l2, l2+ lCnt-1);
righ[root] = build(p+1, r1, l2+lCnt, r2-1); // 要少去最后一个(根)
return root;
}
bool read_list(int *pArr) {
string line;
if (!getline(cin, line))
return false;
stringstream ss(line);
int x;NCNT = 0;
while (ss>>x)
pArr[NCNT++] = x;
return NCNT>0;
}
// ans为最佳的节点的权重 ans_sum为最佳路径权重和
int ans, ans_sum =100000;
// 采用先序遍历获取结果
void dfs(int index, int sum) {
sum += index;
if (!lef[index] && !righ[index]) {
// 此时为叶子节点
if (sum < ans_sum || (sum == ans_sum && index < ans)) {
ans = index;
ans_sum = sum;
}
}
if (lef[index])
dfs(lef[index], sum);
if (righ[index])
dfs(righ[index], sum);
}
int main() {
while (read_list(in_order)) {
read_list(post_order);
build(0, NCNT-1, 0, NCNT -1);
ans_sum = 100000; // 假设为无穷大
dfs(post_order[NCNT-1], 0);
cout<< ans<<endl;
}
return 0;
}