1. 题目描述:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=489
2. 对于二叉树T,可以递归定义它的先序遍历、中序遍历和后序遍历:
a) PreOrder(T)=T的根结点+ PreOrder(T的左子树)+ PreOrder(T的右子树)
b) InOrder(T)= InOrder(T的左子树)+T的根结点+InOrder(T的右子树)
c) PostOrder(T)= PostOrder(T的左子树)+ PostOrder(T的右子书)+T的根结点
d) 这三种遍历都属于递归遍历,或者说深度优先遍历(DFS),因为它总是优先往深处访问
3. 解题思路:
a) 后序遍历的最后一个字符是根,且各个结点的权值各不相同且都是整数,因此只需在中序遍历中找到它,从而得知左右子树的中序和后序遍历。然而,将二叉树构造出来,再执行一次递归遍历,以找到最优解
b) 建立read_list函数,用来读入中序遍历和后序遍历的二叉树并存储到对应的数组中
c) 用DFS找最优解
4.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <algorithm>
using namespace std;
const int maxn=10000+10;
//因为各个结点的权值各不相同且都是正整数,因此直接用权值作为结点编号
int in_order[maxn],post_order[maxn],lch[maxn],rch[maxn];
int n; //n为全局变量,记录结点个数
int best,best_sum; //目前为止的最优解和对应的权和
bool read_list(int *a){
string line;
if(!getline(cin,line))
return false; //输入错误
stringstream ss(line); //从string类型的变量line中读取
n=0;
int x;
while(ss>>x)
a[n++]=x; //n为结点个数
return n>0; //true
}
//把in_order[L1...R1]和post_order[L2...R2]建成二叉树,并返回树根
int build(int L1,int R1,int L2,int R2){
if(R1<L1) //判断是否为空树
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;
}
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)){ //将中序遍历存入in_order中
read_list(post_order); //将第二行的后续遍历存入post_order中
build(0,n-1,0,n-1);
best_sum=10000000000;
dfs(post_order[n-1],0);
cout<<best<<endl;
}
return 0;
}