树 UVa 548

高能预警:此文作者水平极差,漏洞百出,错误俯拾皆是,行文毫无逻辑!仅供自己研究所用。

递归遍历=深度优先搜索=dfs,二叉树中为先序、中序、后序遍历。

或者说是深度优先搜索,我把它称为纵向优先搜索,有点类似于在根节点处倒了很多水,水流下去的感觉。

问题分解:

1、读入和保存。

2、建树。

3、计算每个叶子到根的路径上的权和。

4、比较哪个叶子上权和最小。

5、如果有大于一个叶子权和最小,取出叶子上权最小的那个。

难题:

1、输入中如何区分空格和换行?

2、无论是建树还是dfs,都是递归的思路,但问题是,如何用代码实现?

对于任何一棵二叉树而言,最重要的无非就是那几个量——自身的量、左子树/右子树的编号/地址

在本题中,刘汝佳老师的建树方式是:既然每个节点的权值不同且均为整数,不妨将其作为权值。

新建两个数组,分别来保存左孩子和右孩子。



#include
#include
#include
#include
using namespace std;

const int maxv = 10000 + 10;
int in_order[maxv], post_order[maxv], lch[maxv], rch[maxv];//lch = leftchildren 即左孩子
int n;//结点的个数

bool read_list(int *a) {
    string line;//把每一行中数字和空格合在一起看成字符串,以行为单位来读取,好方法!
    if(!getline(cin, line)) return false;//任何一个多组输入都需要终止条件。getline指的是以流输入的方////式来读入line,当没有读入的时候结束读入。
   stringstream ss(line);//把字符串line变成类似于cin的东西,同属于流式输入。这种输入方式对于新手来说很重要,因为它在处理输入的是字符串,但是只需要数字(不仅仅是这种情况)会有很大作用。
    n = 0;//结点数归零
    int x;
    while(ss >> x) a[n++] = x;//将数字保存在数组中的同时还更新了结点数
    return n > 0;//bool型函数也可以返回整形,因为大于0的数可以看作是true
}
//在中序遍历和后序遍历数组中,把他们各自分成了三部分:左右子树和根节点之后,如何确定左孩子和//右孩子呢?很简单,以左孩子为例:两个数组中左子树的首尾编号传进build函数即可,因为build函
//数一下子就可以找到左子树的根节点!也就是左孩子。接下来的代码就是重复这个过程:把左子树视作//一棵新树,分成三部分:左右子树和根节点

int build(int L1, int R1, int L2, int R2) {
    if(L1 > R1) return 0;//这种是平凡的情况,也就是把所有的叶子节点赋值为0
    int root = post_order[R2];
    int p = L1;//此处易误为0
    while(in_order[p] != root) p++;
    int cnt = p – L1;//左子树节点的个数
    lch[root] = build(L1, p - 1, L2, L2 + cnt – 1);//关于R2做一下说明:根据高中所学的数列知识:个数 //= 末项 – 首项 + 1,那么末项 = 首项 + 个数 - 1
    rch[root] = build(p + 1, R1, L2 + cnt, R2 -1);
    return root;
}

int best, best_sum;//best指的是目前为止的最优解的结点上的值,best_sum就是此时对应的权和

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);
        build(0, n - 1, 0, n – 1);//数组其实就是两个数字之间的映射,和二叉树的本质相同,build函数就是//在给两个数组赋值。
        best_sum = 1000000000;
        dfs(post_order[n-1], 0);/*dfs的作用就是在更新best的值。 这种策略是:把要求的量声明为全局
量,由某个void函数来不断更新它,而不是采用比较低级的——由一个函数来返回所求的值。*/
        cout << best << "\n";
    }
}

你可能感兴趣的:(刘汝佳紫书)