例题6-8 树 UVa 548 Tree
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; }