例题6-8 Tree Uva548

这道题我一直尝试用scanf来进行输入,不过一直没有成功,因此先搁置一下,以后积累些知识再进行尝试。

这道题有两种解决方案:

即先建树,再遍历和边建树边遍历。这两种方案经过实践证实效率相差不太多。应该主要耗时的是cin stringstream 之类的输入函数。

另外,通过这道题领悟了一个非常重要的事情:

一定要清空上组数据使用过的数组,否则后果很严重!!!!!!

除非你确定数组清不清无所谓。

在这里也可以稍微用一些技巧。我在输入的同时将所需要的数组对应下标设为初始值,这样能节省很多时间,特别是在数组非常大的时候,这样通过这种方法能节约近一半的时间:

memset(s,0,sizeof(s));

while(t>=0){
    a[n++] = x;
    lch[x]=0;
    rch[x]=0;
}

这里的输入过程,我采用了两种方案

bool read_line1(int* a){
    if(!fgets(s,sizeof(s),stdin))return false;
    n=0;
    int t=0;
    int x;
    while(t>=0){
        sscanf(&s[t], "%d", &x);
        t = strchr(&s[t], ‘ ‘) + 1 - &s[0];
        a[n++] = x;
        lch[x]=0;
        rch[x]=0;
    }
    return n>0;
}

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;
}

以下是完成AC代码1

#include <sstream>
#include <string>
#include <cstdio>
#include <set>
#include <cstring>
using namespace std;
const int maxn = 100000 + 10;
int n;
int in_order[maxn],post_order[maxn],lch[maxn], rch[maxn];
char s[maxn];
bool read_line(int* a){
   
}
bool read_line1(int* a){
    if(!fgets(s,sizeof(s),stdin))return false;
    n=0;
    int t=0;
    int x;
    while(t>=0){
        sscanf(&s[t], "%d", &x);
        t = strchr(&s[t], ‘ ‘) + 1 - &s[0];
        a[n++] = x;
        lch[x]=0;
        rch[x]=0;
    }
    return n>0;
}
int best,best_sum;
set<int> dict;
int build(int L1, int R1, int L2, int R2, int sum){
    if(L1 > R1){
        return 0;
    }
    int root = post_order[R2];
    sum += root;

if(L1==R1 && !lch[root] && !rch[root]){
                   // printf("%d...%d\n",root,sum);

if(sum<best_sum || sum == best_sum && root<best){
            best_sum = sum;
            best = root;
        }
    }

int p = L1;
    while(in_order[p] != root) p++;
    int cnt = p- L1;
    lch[root] = build(L1,p-1,L2,L2+cnt-1,sum);
    rch[root] = build(p+1,R1,L2+cnt,R2-1,sum);
    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_sum = sum;
            best = u;
        }
    }
    if(lch[u])dfs(lch[u], sum);
    if(rch[u])dfs(rch[u], sum);
}
int main(){
    #ifdef DEBUGI
    freopen("6.8.in","r",stdin);
   // freopen("6.8.out","w",stdout);
    #endif
    #ifdef DEBUGO
    //freopen("6.8.in","r",stdin);
    freopen("6.8.out","w",stdout);
    #endif
    //read_line(in_order);
   
    while(read_line(in_order)){
        read_line(post_order);
        int r=post_order[n-1];
        best_sum = 1000000000;
        build(0,n-1,0,n-1,0);
        //dfs(post_order[n-1],0);
        printf("%d\n",best);
    }
   
    return 0;
}

AC代码2(基本与课本解法一致)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
const int maxv = 10000 + 10;
int best_sum ,best;
int in_order[maxv],post_order[maxv],lch[maxv],rch[maxv];
int n;

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 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]){
   //     printf("*%d*%d*\n",u,sum);
        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);
}
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;
}

int main(){
    #ifdef DEBUGI
    freopen("6.8.in","r",stdin);
   // freopen("6.8.out","w",stdout);
    #endif
    #ifdef DEBUGO
    //freopen("6.8.in","r",stdin);
    freopen("6.8.out","w",stdout);
    #endif
    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);
        cout << best << "\n";
    }
    return 0;
}

之后还要尝试写一下指针版的

时间: 2024-12-11 07:08:11

例题6-8 Tree Uva548的相关文章

二叉树的递归遍历 Tree UVa548

题意:给一棵点带权的二叉树的中序和后序遍历,找一个叶子使得他到根的路径上的权值的和最小,如果多解,那该叶子本身的权值应该最小 解题思路:1.用getline()输入整行字符,然后用stringstream获得字符串中的数字 2.用数组in_oder[]和post_order[]分别表示中序遍历和后序遍历的顺序,用数组rch[]和lch[]分别表示结点的左子树和右子树 3.用递归的办法根据遍历的结果还原二叉树(后序遍历的最后一个树表示的是根节点,中序遍历的中间一个表示根节点) 4.二叉树构造完成后

点分治——POJ 1741

写的第一道点分治的题目,权当认识点分治了. 点分治,就是对每条过某个点的路径进行考虑,若路径不经过此点,则可以对其子树进行考虑. 具体可以看menci的blog:点分治 来看一道例题:POJ 1741 Tree 题目大意:扔给你一颗有权无根树,求有多少条路径的长度小于k: 解题思路:先找出重心,用一次dfs处理出每个点到根的距离dis,然后将dis[]排序,用O(n)的复杂度处理出"过根且长度小于等于k的路径数目",删除根节点,对于每棵子树重复上述操作. 注意要去重: 像上面这样一个图

数据结构虐哭空巢老人记

数据结构虐哭空巢老人记 前言 \(\cal STO\ f啦sh\ ORZ\) by 去不了冬令营的徐叔叔 搞过的东西就不再写了(数组队列栈链表.线段树动态树替KD树树状数组Splay替罪羊Treap.线段树合并Trie合并.可持久化Trie可持久化线段树.线段树优化DP优化连边) 要写的是 李超线段树 吉利线段树 线段树分裂 虚树 树链的并 还要进一步学习 线段树分治 二进制分组 珂朵莉树 数据结构题注意点 如果更新某点,为了方便访问到其孩子,那么线段树要开8倍空间.否则4倍空间就好了 李超线段

UVA548——Tree

Tree You are to determine the value of the leaf node in a given binary tree that is the terminal node of a path of least value from the root of the binary tree to any leaf. The value of a path is the sum of values of nodes along that path.Input The i

UVA548 Tree (二叉树的遍历)

You are to determine the value of the leaf node in a given binary tree that is the terminal node of a path of least value from the root of the binary tree to any leaf. The value of a path is the sum of values of nodes along that path. Input The input

Palindromic Tree 回文自动机-回文树 例题+讲解

---恢复内容开始--- 回文树,也叫回文自动机,是2014年被西伯利亚民族发明的,其功能如下: 1.求前缀字符串中的本质不同的回文串种类 2.求每个本质不同回文串的个数 3.以下标i为结尾的回文串个数/种类 4.每个本质不同回文串包含的本质不同回文串种类 (本文参考自Palindromic Tree——回文树[处理一类回文串问题的强力工具],Palindromic Tree 回文自动机-回文树 解决回文串的神器) 下面介绍一些数组的意义 next[][]类似于字典树,指向当前字符串在两段同时加

UVA548 Tree

从这个题目我们再次学习到了一个知识点,就是递归函数的强大! 首先,我们先明确一个知识点,就是你知道了一棵树的中序和后序遍历,求他的前序遍历,我们应该怎么来做? 第一步:最初的时候,我们的后序遍历的最后一个数字就是我们的一个子树的根节点 第二步:找到我们的根结点后,跟据我们中序遍历的性质,我们的树就会被自然地分成了左右两个部分. 第三步:统计出来左右两个子树的大小和长度,这样就能继续重复上面的步骤 这道题的读写输入也是一个知识点,这个我是直接看的刘汝佳的知识点来做的. 总之,递归很强大很强大! #

UVa548 Tree (二叉树)

链接:http://acm.hust.edu.cn/vjudge/problem/19105分析:由中序遍历和后序遍历可以唯一确定一棵二叉树.后序遍历中最后一个元素就是树根,然后在中序遍历中找到它,从而可以找出以它为根结点的左右子树的结点列表,然后再递归构造左右子树.这道题由于权值各不相同,且都是小于10000的正整数,可以以权值作为结点编号建树.边建树边统计最优解,best为最优解叶子结点权值也即叶子结点编号,best_sum为最优权值和,这两个变量作为全局变量,因为每个可行解都要与当前最优情

例题6-8 树 UVa548

1.题目描述:点击打开链接 2.解题思路:本题给出了一颗二叉树的中序遍历和后序遍历,要求找一个叶子,使得它到达根结点的权和最小,如果有多解,那么该叶子自身的权应该尽量小.首先,根据中序遍历和后序遍历建立二叉树,这道题采用数组来存放左右子树的结点值,根为root的左子树结点为lch[root]右子树结点为rch[root]. 那么,如何根据中序遍历,后序遍历来建树呢?方法是根据后序遍历找到根,然后在中序遍历中找到树根,从而找出了左右子树的结点列表,然后递归构造左右子树即可.最后利用先序遍历来求解最