树的直径(c++)
·
树的直径的定义:树上任意两节点之间最长的简单路径即为树的直径。
树的直径的求法有两种,一种是求两次DFS,一种是用树形DP。
https://www.luogu.com.cn/problem/B4016 模板题链接
1、利用两次DFS遍历:
首先以任意节点为起始点找到以该节点为根的最深点(可能有多个,不影响)DFS找到最深点idx,再以该点为根DFS,得到的深度就是直径。为求简易,以1为根。
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
const int INF = 0x7fffffff;
vector<int>g[N]; int idx;//使用邻接表,比邻接矩阵快 idx为下标,记录第一次DFS最深点
int n, a, b; int siz[N];//n为节点数,siz数组记录深度
void dfs(int u, int f) {
for (const auto& x : g[u]) {
if (x == f)continue;
siz[x] = siz[u] + 1;//子节点的深度为父节点深度加1
if (siz[x] > siz[idx]) {//找到最深节点并更新
idx = x;
}
dfs(x, u);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n;
for (int i = 1; i < n; i++) {
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
//输入图
}
dfs(1, 0);//第一次遍历,找到最深节点
siz[idx] = 0;//一定要初始为0
dfs(idx, 0);//第二次遍历,找到最深节点,这个节点和根节点idx之间的长度就是直径
cout << siz[idx];
return 0;
}
2、树形DP
树形DP就是分别以各节点为根,求最长和次长的两条边,直径就是这两条边相加最大的值。
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
int n, ans;
int dp[N][2];//dp数组,其中0和1分别最大值和次大值
vector<int>g[N];//邻接表
void dfs(int u, int f) {
for (const auto& x : g[u]) {
if (x == f)continue;
dfs(x, u);
int t = dp[x][0] + 1;
if (t > dp[u][0]) {
//该条边的长的大于最长的那条边,则该条边成为最长边,原最长边成为次长边
dp[u][1] = dp[u][0];
dp[u][0] = t;
}
//该条边小于最长边,但大于次长边,更新次长边即可
else if (t > dp[u][1]) {
dp[u][1] = t;
}
}
ans = max(ans, dp[u][0] + dp[u][1]);
//以每个点为根进行树形DP,不断更新,找到直径
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n;
for (int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
//输入
}
dfs(1, 0);
cout << ans;
return 0;
}
两种方法在节点为正权时都可以使用,但如果节点存在负权,我们只能使用树形DP
如有不懂,欢迎在评论区留言。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)