C++树形结构(2 树的直径)

目录

1.定义:

2.直径的性质:

3.树的直径求解方法:

4.直径端点求解方法:

朴素方法:

优化方法:

5.例题:

6.直径公共点:

7.例题:

8.去掉再加上:

9.例题:


1.定义 :

树的直径是树上两点间距离的最大值。即树中最远的两个节点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链

最长链:4-2-1-7-6-3

所以这颗树的直径是15,直径路径为4-2-1-3-6

2.直径的性质:

直径的性质1:直径的端点一定是叶子节点

直径的性质2:任意点的最长链端点一定是直径端点

直径的性质3:如果一棵树有多条直径且边权都为正,那么它们必然相交,且有极长连续段(可以是一个点,交点为树的中心)

直径的性质4:树T1的直径为x,y,树T2的直径为s,t。现有一边u,v与两颗树相连,新树的直径端点一点是x,y,s,t中的两个

3.树的直径求解方法:

引理性质2:任意点的最长链端点一定是直径端点。方法:我们随意找一个点x,进行dfs找到最长链的端点s,再以端点s做第二遍dfs,此时可以找到直径的第二个端点t。此时端点s到t的距离就是树的直径。

输入一颗无根树,第一行为一个正整数n(n<1e5),表示这颗树有n个节点接下来的n−1行,每行三个正整数u,v,w,表示u,v(u,v<=n)有一条权值为w(w<100)的边相连,求树的直径。 

#include<bits/stdc++.h>
using namespace std;
int n,data[100005],pl,maxn;
vector<int> v[100005];
vector<int> w[100005];
void dfs(int x,int fa) {
	for(int i=0; i<v[x].size(); i++) {
		int y=v[x][i];
		if(y==fa) continue;
		data[y]=data[x]+w[x][i];
		if(data[y]>maxn) maxn=data[y],pl=y;//记录端点
		dfs(y,x);
	}
}
int main() {
	cin>>n;
	for(int i=1; i<n; i++) {
		int x,y,z;cin>>x>>y>>z;
		v[x].push_back(y);
		v[y].push_back(x);
		w[x].push_back(z);
		w[y].push_back(z);
	}
	dfs(1,0);//寻找直径
	memset(data,0,sizeof data);//清空距离
	dfs(pl,0);//从pl出发寻找端点
	cout<<maxn;
	return 0;
}

4.直径端点求解方法:

我们通过记录父亲节点的方式能够把直径上的所有点全部记录下来。在树中,直径端点是常用点(假设端点为s,t),我们树上任意一点p所能到的最大距离,只有可能是到ps或pt

那如何找到所有点到两个直径端点的距离?

朴素方法:

求出直径端点后,以每个点为根做dfs,找到根节点到端点的距离。复杂度O(N2)。

优化方法:

第一次从任意点出发,必然能到达直径的一个端点s。第二次从s点进行dfs找到端点t,此时记录所有点到s的距离。第三次从t点进行dfs,记录所有点到t的距离。复杂度:O(n)

5.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值