UVA-548 Tree(二叉树,DFS)

这篇博客介绍了如何解决UVA-548问题,涉及二叉树的DFS搜索。通过结合中序和后序遍历来重建二叉树,并找到具有最小路径权值的叶子节点。文章强调了先序遍历在求和中的作用,并提供了代码实现,包括二叉树的构建和DFS函数。

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

初识二叉树,依葫芦画瓢,主要记录一下。

题目:UVA-548

题目描述:
一棵二叉树,每个结点都有不同的权值(1~10000的正整数),给出了其中序遍历(第一行)和后序遍历(第二行),找到一个叶子,使得它到根的路径的权和最小,如果有多解,该叶子的本身的权值应尽量小。

首先是对DFS的理解。在这里插入图片描述
先序遍历(根->左子树->右子树):ABDECF
中序遍历(左子树->根->右子树):DBEACF
后序遍历(左子树->右子树->根):DEBFCA

先序+中序 或 后序+中序 都可以确定一棵二叉树。(先序+后序无法确定)

以该题的后序+中序和上图为例,对任意一颗二叉树(可能是一个子树),已知后序和中序。

①取后序遍历(DEBFCA)的最后一个结点,一定是当前树的根结点,所以根为A。
②已知根为A,到中序遍历(DBEACF)中查找A的位置,然后可知DBE为左子树,CF为右子树。
(实际编写程序是得到左、右子树的结点数量,即其在中序遍历中是第几个到第几个)
③知道左、子树结点数量,即可得出后序遍历中前3个(DEB)为左子树,随后2个(FC)为右子树。
④上述操作就得到了左、右子树的后序+中序,然后对其进行相同的操作。

Ps.
①在叶结点到根结点路径求和时,应使用先序遍历,其求和顺序是:ABD、ABE、ACF。
②因为是用数组实现二叉树,各个结点权值不同,直接用权值作为结点编号,就不需要另外用数组存结点了。

以下代码:

预处理:

#include<iostream>
#include<sstream>
#include<string>
using namespace std;
const int maxv = 10010;
int  in[maxv], post[maxv], Left[maxv], Right[maxv];   //in为中序,post为后序
int n,min_sum, ans;  //n为结点数量,min_sum最小权和

读取:

bool read(int *a)
{
	string line;              //先把一行放入line中
	if (!getline(cin, line))
		return false;         //读到EOF则返回false
	stringstream ss(line);    //将line创建为流
	n = 0;
	int x;
	while (ss >> x)           //从流中读出
		a[n++] = x;
	return true;
}

构建二叉树:

//L1~R1为当前树所有结点的中序遍历,L2~R2为当前树所有结点的后序遍历
int build_tree(int L1, int R1, int L2, int R2)
{
	if (L1 > R1)    //树为空
		return 0;
	int root = post[R2];         //取根结点
	int p,cnt;
	for (p = L1; p <= R1; p++)   //在中序遍历中找到根结点
		if (in[p] == root)
			break;
	cnt = p - L1;        //左子树的结点数量
	Left[root] = build_tree(L1, p - 1, L2, L2 + cnt - 1);   //左子树的中序、后序
	Right[root] = build_tree(p + 1, R1, L2 + cnt , R2-1);   //右子树的中序、后序
	return root;         //返回当前树的根
}

Ps.这里对空树的判断,举个例子方便理解。假设一个结点其左子树为空,那么会得到p== L1 ==R1,所以递归左子树的时候L1>R1,就可以返回0(代表空树)。

DFS求最小权和:

void dfs(int u, int sum)         //要把当前算得的sum传给下一层
{
	sum += u;
	if (!Left[u] && !Right[u])   //判断为叶结点
	{
		if (sum < min_sum || (sum == min_sum && u < ans))
		{
			ans = u;
			min_sum = sum;
		}
	}
	if (Left[u])
		dfs(Left[u], sum);
	if (Right[u])
		dfs(Right[u], sum);
}

主函数:

int main()
{
	while (read(in))
	{
		read(post);
		int tree=build_tree(0, n - 1, 0, n - 1);  //tree存放根节点
		min_sum = 1000000000;
		dfs(tree, 0);
		cout << ans << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值