树 UVa 548 6.3.3

 给一棵点带权(权值各不相同 ,都是小于10000的正整数)的二叉树的中序和后序遍历,找一个叶子结点使得它到根节点的路径上的权和最小。如果有多解,该叶子本身的权应尽量小,输入中每两行表示一棵树,其中第一行为中序遍历,第二行为后序遍历。
样例输入
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
样例输出
1
3
255
题记
本题最重要的一点就是要知道,通过一棵树的中序遍历和后序遍历可以唯一确定一棵二叉树,并且后序遍历的最后一个就是这颗二叉树的根节点,在中序遍历当中,根结点左边的就是左子树,右边的就是右子树。因为本题比较特殊,所有结点的权值各不相同,所以可以根据权值来用数组唯一标识一个结点,而不用结构体。

代码如下

#include <iostream>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;

const int maxv=10000+10;
int in_order[maxv],post_order[maxv],lch[maxv],rch[maxv];//中序遍历,后序遍历,左孩子,有孩子
int n; //记录节点个数

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; //判断是不是空树
}
//L1,R1是中序遍历数组中当前这棵树的起点和终点,L2,R2同理
int build(int L1,int R1,int L2,int R2){
    if(L1>R1)
        return 0;  //临界条件,到了叶子结点根据后面的公式R1将会等于L1-1
    int root=post_order[R2];  //当前这棵树的根节点就是后序遍历最后的那个节点
    int p=L1;   //p用来找并记录根节点在中序遍历中的编号(下标),这样就可以得到左子树的节点数目,进而推算右子树节点数目
    while(in_order[p]!=root)
        p++;
    int cnt=p-L1;//cnt记录左子树的节点数目
    lch[root]=build(L1,p-1,L2,L2+cnt-1);
    rch[root]=build(p+1,R1,L2+cnt,R2-1);
    return root;  //返回root的值作为上一层(父节点)的左孩子或者右孩子的值
}

int best,best_sum;//最优的叶子的权值,最优的路径的权值

void dfs(int u,int sum){  //u记录当前节点的值,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);
        build(0,n-1,0,n-1);
        best_sum=1000000000;
        dfs(post_order[n-1],0);
        printf("%d\n",best);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值