UVa 548 树(已知其中两种遍历, 还原树)

题意:

给出后序遍历和先序遍历, 还原一棵树, 然后求出从根节点到叶子的最小路劲和。

分析:

已知后序遍历, 那么后序的最后一个节点就是根节点, 然后在中序中找到这个节点, 它的左边就是左子树, 它的右边就是右子树, 然后递归下去。

技巧是不断的变动[r1,l1] [r2,l2]

r1 l1是中序的区间 r2 l2是后序的区间

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 10;
int In_order[maxn], Post_order[maxn], lch[maxn], rch[maxn];
int tot, cnt;
//[L1,R1] , [L2,R2];
bool read(int* a){
    string t;
    if(!getline(cin, t))
        return false;
    int n = 0, x;
    stringstream ss(t);
    while(ss >> x) a[n++] = x;

    tot = n;
    if(n == 0) return false;
    else return true;
}
int bulid(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  pcnt = p - L1;
    lch[root] =  bulid(L1, p-1,L2, L2 + pcnt -1);
    rch[root] =  bulid(p+1, R1,L2 + pcnt, R2 - 1);
    return root;
}
int best_sum = 1e9, best;
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(In_order)){
        memset(lch,0,sizeof(lch));
        memset(rch,0,sizeof(rch));
        best_sum = 1e9, best = 0;
        read(Post_order);
        cnt = 0;
        bulid(0,tot-1,0,tot-1);
        dfs(Post_order[tot-1],0);
        printf("%d\n", best);
    }
    return 0;
}
时间: 2024-11-08 07:17:31

UVa 548 树(已知其中两种遍历, 还原树)的相关文章

根据二叉树的两种遍历求二叉树的结构

二叉树的前序遍历顺序是:根节点,左树,右树 中序遍历顺序是:左树,根节点,右树 后序遍历顺序是:左树,右树,根节点 上面这棵树的前序遍历是:abfcjm   中序遍历是:fbcamj  后序遍历是:fcbmja 根据前序遍历和后序遍历是不能求出树的唯一结构的, 已知的两种遍历顺序必须必须包括中序遍历,因为中序遍历能够递归的推出根节点的左树和右树 如上题已知   前序遍历是:abfcjm   中序遍历是:fbcamj  那么根据前序遍历就可以知道树根是a, 再根据中序遍历就可以知道以a为根节点左树

已知二叉树的前序遍历和中序遍历,如何得到它的后序遍历?

对一棵二叉树进行遍历,我们可以采取3中顺序进行遍历,分别是前序遍历.中序遍历和后序遍历.这三种方式是以访问父节点的顺序来进行命名的.假设父节点是N,左节点是L,右节点是R,那么对应的访问遍历顺序如下: 前序遍历    N->L->R 中序遍历    L->N->R 后序遍历    L->R->N /***************************************************************************************

邻接矩阵(以顶点为中心),比较稀疏时,采用邻接表;图的两种遍历(邻接矩阵实现)

对于边比较稠密的图,可以采用邻接矩阵(以顶点为中心)的方式表示,而边比较稀疏时,采用邻接表的结构更合适.两种都不能直观表达哪两个点相连或者最短路径是什么. 深度优先遍历类似于树的先根序遍历.与树不同的是,它需要对已经访问过的节点添加标记以免被重复遍历. public class Depth { /** * 对k号节点深度遍历 * @param a * @param color * @param k 节点 */ public static void depthTraversal(int[][] a

Delphi 查找标题已知的窗口句柄,遍历窗口控件句柄(转)

Delphi 查找标题已知的窗口句柄,遍历窗口控件句柄(转) 用我的方法来控制其他程序窗体上的窗口控件,必须先了解什么是 回调函数.我的理解是这样的: 回 调函数写出来不是自己的程序去调用的,反而是让其他的东西去调用,比如windows操作系统,比如其他的程序等等之类的.但是什么时候被调用却不知道 了.回调函数一般是按照调用者的要求定义好参数和返回值的类型,你向调用者提供你的回调函数的入口地址,然后调用者有什么事件发生的时候就可以随时按照你 提供的地址调用这个函数通知你,并按照预先规定好的形式传

图的两种存储(邻接矩阵和邻接表)和两种遍历(DFS和BFS)

图的表示有很多,形式不固定,我暂时先记录我已经懂了的,能写的两种即大多数人应该都知道的邻接矩阵和邻接表. 邻接矩阵: 这里的邻接矩阵和离散数学说的有一点不同,至少有向图的邻接矩阵不同(离散书上的有向图的邻接矩阵求法到是有点像求任意两点的最短路径的Floyd算法) 以上都是(我现有知识认为的)废话: 重点 : G : 表示图: Nv:表示图的点数: Ne:表示图的边数: 邻接矩阵 即是一个 Nv * Nv 的矩阵,矩阵是用来储存  权值的(如果是带权图且有边的话),如果是无权图的的话,如果两顶点有

图的两种遍历

两种遍历方法都使用了Visited[]这个数组来记录已经访问的节点 DFS(广度优先) 从头结点开始递归的来调用相邻的节点 void Visit( Vertex V ) { printf("正在访问顶点%d\n", V); } /* Visited[]为全局变量,已经初始化为false */ void DFS( LGraph Graph, Vertex V, void (*Visit)(Vertex) ) { /* 以V为出发点对邻接表存储的图Graph进行DFS搜索 */ PtrTo

已知二叉树的前序遍历结果和中序遍历结果,请重建原来的二叉树

分析的过程: 1.假设前序遍历的第一个值为a,该值就是原二叉树的根节点. 2.在中序遍历结果中查找a. 则在中序遍历中a前面的节点,就是原二叉树a节点左子树的中序遍历结果:在a后面的节点,就是原二叉树a节点右子树的中序遍历结果. 3.由第二步得到a节点左子树的节点个数为m,那么在前序遍历中a后面的m个节点即为a节点左子树的前序遍历结果: 4.由第二步得到a节点右子树的节点个数为n,那么在前序遍历中最后n个节点即为a节点右子树的前序遍历结果: 由此我们可以得到a节点左子树和右子树的前序遍历和中序遍

List集合中两种遍历方式

遍历List集合中的元素的方法有两种: 第一种:利用迭代器遍历 代码1: // 迭代器 Iterator it=list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } 或者代码2: for(Iterator it=list.iterator();it.hasNext();) { System.out.println(it.next()); }// 与while循环相比优点:对象it在循环结束后,变为垃圾,自动

Map的两种遍历方式

********************************************************************************* *****************************Map两种遍历方式******************************* ********************************************************************************* 1 package ccms;