树的直径

树的直径即为一棵树上的最长链。一般分为有负权图和无负权图来考虑。

无负权
只需做两次dfs。
第一次是搜索出从任一点出发到达的最远的点P,那么这个点就一定在最长链上(请自证)。
第二次搜索从点P出发到达的最远的点Q,那么最长链即为P与Q的距离。

题目:B4016 树的直径

代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, lth[N], ans, mx, pas;
vector <int> e[N];
void dfs(int u, int fa)
{
	lth[u] = lth[fa] + 1;
	if(lth[u] > mx) mx = lth[u], pas = u;
	for(int i = 0; i < e[u].size(); i ++)
	{
		if(e[u][i] == fa) continue;
		dfs(e[u][i], u);
	}
}
int main()
{
	cin >> n;
	int u, v;
	for(int i = 1; i < n; i ++)
	{
		scanf("%d %d", &u, &v);
		e[u].push_back(v), e[v].push_back(u);
	}
	dfs(1, 0);
	mx = 0;
	memset(lth, 0, sizeof(lth));
	dfs(pas, 0);
	ans = mx;
	cout << ans - 1 << endl;
	return 0;
}

有负权
前面的做法显然不能解决这类问题,那么我们考虑树形dp(其实也是搜索)
接下来介绍两种做法,都要先确定根节点,以下的链都是以某点为子树的根,到达子节点的长度。

题目:U81904 【模板】树的直径

  1. 记录每个点出发的最长链和次长链(链没有公共边)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n, d1[N], d2[N], d;
vector <int> E[N], W[N];
void dfs(int u, int fa)
{
	for(int i = 0; i < E[u].size(); i ++)
	{
		int v = E[u][i], val = W[u][i];
		if(v == fa) continue;
		dfs(v, u);
		int t = d1[v] + val;
		if(t > d1[u]) d2[u] = d1[u], d1[u] = t;
		else if(t > d2[u]) d2[u] = t;
		d = max(d, d1[u] + d2[u]);
	}
}
int main()
{
	cin >> n;
	for(int i = 1; i < n; i ++)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		E[u].push_back(v), E[v].push_back(u);
		W[u].push_back(w), W[v].push_back(w);
	}
	dfs(1, 0);
	printf("%d\n", d);
	return 0;
}
  1. 直接记录最长链,答案就是最长链与该节点出发的另一链的和(本质就是次长链,但是写起来比较方便)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n, d, dp[N];
vector <int> E[N], W[N];
void dfs(int u, int fa)
{
	for(int i = 0; i < E[u].size(); i ++)
	{
		int v = E[u][i], val = W[u][i];
		if(v == fa) continue;
		dfs(v, u);
		d = max(d, dp[u] + dp[v] + val);
		dp[u] = max(dp[u], dp[v] + val);
	}
}
int main()
{
	cin >> n;
	for(int i = 1; i < n; i ++)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		E[u].push_back(v), E[v].push_back(u);
		W[u].push_back(w), W[v].push_back(w);
	}
	dfs(1, 0);
	printf("%d\n", d);
	return 0;
}
posted @   小队长wtz  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示