2021-04-25 树 uva 548

本文介绍了一种算法,通过给定的二叉树中序和后序遍历序列,寻找从根节点到叶子节点数值总和最小的路径,并输出该路径上的叶子节点值。提供了三种实现方式,包括使用数组存储二叉树结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

题意翻译

输入一个二叉树的中序和后序遍历,请你输出一个叶子节点,该叶子节点到根的数值总和最小,且这个叶子是编号最小的那个。 输入: 您的程序将从输入文件中读取两行(直到文件结尾)。第一行是树的中序遍历值序列,第二行是树的后序遍历值序列。所有值将不同(因为所有值不同且有限所以可以用数组保存)(下面有两种建树方法),大于零且小于或等于10000.二叉树的节1<=N<=10000。 输出: 对于每个树描述,您应该输出最小值路径的叶节点的值。存在多路径最小的情况下,您应该选择终端叶子节点上具有最小值的那条路径,且输出那个最小值的终端叶子。

Translated by @凉凉

输入输出样例

输入 #1复制

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复制

1
3
255
//抄书,用数组存树;
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAX = 10010;
int in_order[MAX], post_order[MAX],lch[MAX],rch[MAX],n;
bool read_list(int* a) {
	string s;
	if(!getline(cin,s))return false;
	n = 0;
	stringstream ss(s);
	//ss << s; //cout << s<<endl;
	int x;
	while (ss>>x) {
		a[n++] = x;
	}
	return n > 0;
}
int build(int L1,int R1,int L2,int R2) {
	if (L1 > R1)return 0;
	int root = post_order[R2];
	int p = L1;//not 0;
	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;
}
int best, best_sum;
void dfs(int root,int sum) {
	sum += root; //cout << root<<endl;
	if (!lch[root] && !rch[root]) {
		if (best_sum > sum || (best_sum == sum && best > root))
		{
			//cout << "*"<<root<<' '<<sum<<endl;
			best = root;
			best_sum = sum;
		}
		return;
	}
	if(rch[root])dfs(rch[root], sum);
	if(lch[root])dfs(lch[root], sum);
}

int main()
{
	while (read_list(in_order)) {
		read_list(post_order);
		build(0, n - 1, 0, n - 1);
		best_sum = INT_MAX;
		dfs(post_order[n-1],0);
		cout << best<<endl;
	}
	return 0;
}
//重写:数组保存2叉树
#include <iostream>
#include <cstring>
#include <string>
#include <sstream>
#include<limits.h>
using namespace std;
//每个节点的左子树和右子树的值,用值直接作为下表,索引下一个值
int lch[10010], rch[10010];
int mid[10010], back[10010];//保存中序后序的值
int root;
int sum,minn = INT_MAX,minroot;//记录最小值和最小值对应的节点值
string s;
int read()
{
    
    if(!getline(cin,s))return 0;
    stringstream ss;
    int cnt = 0;
    ss << s;
    while (ss >> mid[cnt++]);
    cnt = 0;
    getline(cin, s);
    ss.clear();
    ss.str(s);
    while (ss >> back[cnt++]);
    return cnt-1;
}
int build(int l1, int r1, int l2, int r2)
{//递归建树,由后序遍历最后一个是该树的根节点,在中序遍历中找到,
 //它左边的是左子树右边是右子树,递归。。。
    if (l1 > r1)return -1;//用-1 表示空节点;
    int root = back[r2];
    int p = l1;
    while (mid[p] != root)p++;
    //int len = r1 - l1 + 1;//总长度
    //int llen = p;//左子树长度
    int llen = p - l1;//忘记剪掉左边界
    lch[root] = build(l1, p - 1, l2, l2 + llen - 1);
    rch[root] = build(p + 1, r1, l2 + llen , r2 - 1);
    return root;
}
void dfs(int root)
{//搜索最小路径
    sum += root;
    if (lch[root] == -1 && rch[root] == -1) {
        if (minn >= sum) {
            if (minn == sum) {
                if (minroot > root) {
                    minroot = root;
                }
            }
            else {
                minn = sum;
                minroot = root;
            }
        }
        sum -= root;
        return;
    }
    //sum += root;这一步应该放到前面,先加上该节点的值才完成搜索。
    if (lch[root] != -1) {
        dfs(lch[root]);
    }
    if (rch[root] != -1) {
        dfs(rch[root]);
    }
    sum -= root;
}
int main()
{
    int p;
    while (p = read()) {
        minn = INT_MAX;
        root = build(0, p-1, 0, p-1);
        dfs(root);
        cout << minroot << endl;
        memset(mid, 0, sizeof(mid));
        memset(back, 0, sizeof(back));
        memset(lch, 0, sizeof(lch));
        memset(rch, 0, sizeof(rch));
    }
    return 0;
}

 

//指针建树
#include<iostream>
#include<limits.h>
#include<string>
#include<cstring>
#include<sstream>
using namespace std;
int n,minn,sum,minroot;
int mid_[10010], back_[10010];
struct tree {
	int val;
	tree* left, * right;
	tree() {
		val = 0;
		left = nullptr;
		right = nullptr;
	}
};
tree* build(int l1, int r1, int l2, int r2)
{
	if (l1 > r1)return nullptr;
	tree* rt = new tree();
	rt->val = back_[r2];
	int p = 0;
	while (mid_[p] != rt->val)p++;
	int llen = p - l1;
	rt->left = build(l1, p - 1, l2, l2 + llen - 1);
	rt->right = build(p + 1, r1, l2 + llen, r2 - 1);
	return rt;
}
int read()
{
	string s;
	int cnt=0,p;
	getline(cin, s);
	if (s.empty())return 0;
	stringstream ss(s);
	while (ss >> p) {
		mid_[cnt++] = p;
	}
	ss.clear();
	getline(cin, s);
	ss.str(s);
	cnt = 0;
	while (ss >> p) {
		back_[cnt++] = p;
	}
	return cnt;
}
void dfs(tree* root)
{
	sum += root->val;
	if (!root->left && !root->right) {
		if (minn >= sum) {
			if (minn == sum) {
				if (minroot > root->val)minroot = root->val;
			}
			if (minn > sum) {
				minn = sum;
				minroot = root->val;
			}
		}
		//sum -= root;
		//return;//此处不应该直接回溯,回溯前要减去本节点的值;
	}
	if (root->left)dfs(root->left);
	if (root->right)dfs(root->right);
	sum -= root->val;
}
int main()
{
	while (n = read()) {
		tree* root = new tree();
		root = build(0, n - 1, 0, n - 1);
		minn = INT_MAX;
		sum = 0;
		dfs(root);
		cout << minroot<<endl;
		memset(mid_, 0, sizeof(mid_));
		memset(back_, 0, sizeof(back_));
		delete(root);
	}
	return 0;
}
//4.28 复习数组存树
#include<iostream>
#include<limits.h>
#include<string>
#include<cstring>
#include<sstream>
using namespace std;
int n,minn,sum,minroot;
int mid_[10010], back_[10010], lch[10010], rch[10010];
int build(int l1, int r1, int l2, int r2)
{
	if (l1 > r1)return 0;
	int rt = back_[r2];
	int p = l1;
	while (mid_[p] != rt)p++;
	int llen = p - l1;
	lch[rt] = build(l1, p - 1, l2, l2 + llen - 1);
	rch[rt] = build(p + 1, r1, l2 + llen, r2 - 1);
	return rt;
}
int read()
{
	string s;
	int cnt=0,p;
	getline(cin, s);
	if (s.empty())return 0;
	stringstream ss(s);
	while (ss >> p) {
		mid_[cnt++] = p;
	}
	ss.clear();
	getline(cin, s);
	ss.str(s);
	cnt = 0;
	while (ss >> p) {
		back_[cnt++] = p;
	}
	return cnt;
}
void dfs(int root)
{
	sum += root;
	if (!lch[root] && !rch[root]) {
		if (minn >= sum) {
			if (minn == sum) {
				if (minroot > root)minroot = root;
			}
			if (minn > sum) {
				minn = sum;
				minroot = root;
			}
		}
		//sum -= root;
		//return;//此处不应该直接回溯,回溯前要减去本节点的值;
	}
	if (lch[root])dfs(lch[root]);
	if (rch[root])dfs(rch[root]);
	sum -= root;
}
int main()
{
	while (n = read()) {
		int root = back_[n-1];
		build(0,n-1,0,n-1);
		minn = INT_MAX;
		sum = 0;
		dfs(root);
		cout << minroot<<endl;
		memset(mid_, 0, sizeof(mid_));
		memset(back_, 0, sizeof(back_));
		memset(lch, 0, sizeof(lch));
		memset(rch, 0, sizeof(rch));
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值