树上任意两点都是连通的,相互可达的。
找树的直径:
(一)DFS || BFS,(树上最远的两个点之间的距离,相邻两个点之间距离为1)
1. 任取一点作为起点,找到距离该点最远的一个点 u。u 一定是某条直径的一个端点。DFS || BFS(BFS更优,防止爆栈)
2. 再找到距离 u 最远的一点 v。DFS || BFS(BFS更优,防止爆栈)
那么 u 和 v 之间的路径就是一条直径。
(二)从树形dp角度看,使用DFS,(边权为正负均可)
我们把每一个点归为一类,然后将每条路径归到它所经过的最高的那个点的这一类里。于是,我们可以按点将所有的路径分类。然后我们枚举每个点,对于每个点,再枚举挂在该点上的所有路径即可,求出这些路径长度的最大值。对于每个点求最大值的过程中,先求出每个子节点向下走的最大长度。可以分为两类:一类是路径以该点作为端点,那么就是求从这个点向下走最远能走多少。此时枚举所有子节点能向下走的最大距离,再各自加上从该点到子节点这条边的长度,从中取最大值即可。第二类是该点为路径中的某一点(非端点),路径穿过这个点,那么我们就求从该点向下能够走的最长路径和次长路径之和。给一堆数,求最大值和次大值,只需遍历一遍,不需要排序。如果当前数大于最大数,我们就把最大数赋给次大数,然后更新最大数,否则,我们再判断当前数如果大于次大数,那么我们更新次大数。
https://www.acwing.com/problem/content/1074/
#include <bits/stdc++.h> using namespace std; const int maxn = 2e4 + 7; //由于边有正反两个方向,所以扩大一倍 int n, cnt, ans; int head[maxn]; struct edge { int from, to, next, w; }e[maxn]; void add(int u, int v, int w) { e[++cnt].next = head[u]; e[cnt].from = u; e[cnt].to = v; e[cnt].w = w; head[u] = cnt; } int dfs(int u, int father) { int dist = 0; int d1 = 0, d2 = 0; for(int i = head[u]; i; i = e[i].next) { int j = e[i].to; if(j == father) continue; int d = dfs(j, u) + e[i].w; dist = max(dist, d); if(d >= d1) d2 = d1, d1 = d; else if(d > d2) d2 = d; } ans = max(ans, d1 + d2); return dist; } int main() { scanf("%d", &n); for(int i = 0; i < n - 1; ++i) { int u, v, w; scanf("%d %d %d", &u, &v, &w); add(u, v, w), add(v, u, w); } dfs(1, -1); printf("%d ", ans); }
(三)