树的直径
题目描述
给定一棵树,树中包含 n个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。
现在请你找到树中的一条最长路径。
注意:路径中可以只包含一个点。
输入描述
第一行包含整数 n。
接下来 n−1 行,每行包含三个整数 ai,bi,ci表示点 ai和 bi 之间存在一条权值为 ci 的边。
输出描述
输出一个整数,表示树的最长路径的长度。
数据范围
1≤n≤100001≤n≤100001≤n≤10000
1≤ai,bi≤n,1≤ai,bi≤n,1≤ai,bi≤n,
0≤ci≤1050≤ci≤10^50≤ci≤105
样例
输入
6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7
输出
22
思路
首先,由于本题的数据范围在10000,所以我们可以确定要用链式前向星来存这棵树
那么重嗦粥只,树的直径可以通过两条性质来求解:
①取树上任一点,树上到该点距离最长的点必是某一条直径的端点
②一条直径的端点,树上到该端点距离最短的点即为该直径的另一条端点
那么根据这两条性质可得,只要我们任找一个点,以它为起点找一个离他最远的点,再以找到的点为起点找一个离他最远的点即可确定一条直径
遍历树,无非就是深搜和广搜选一个,这个题显然两个都可以,我们就拿深搜举个例子
这个题深搜比较与众不同的点就一个但也比较常见:长度计数器
其实就是在递归里增加一个计数器取最小值
然后只要以找到的节点为起点重复调用一遍dfs函数即可
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
//链式前向星加边函数
int e[20005], ne[20005], head[10005], w[20005], idx = 0;
void add(int a, int b, int c) {
e[idx] = b;
ne[idx] = head[a];
w[idx] = c;
head[a] = idx++;
}
int sum = 0;
int node;
void dfs(int x, int fa, int an) {
//取最大子树长度
if (an > sum) {
sum = an;
node = x;
}
int y;
for (int i = head[x]; i != -1; i = ne[i]) {
//假如搜重了就跳出
if (e[i] == fa) {
continue;
}
y = e[i];
dfs(y, x, an + w[i]);
}
}
int main() {
scanf("%d", &n);
memset(head, -1, sizeof(head));
int x, y, z;
for (int i = 1; i <= n - 1; i++) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
dfs(1, -1, 0);
sum = 0; //记得要把sum清空一遍
dfs(node, -1, 0);
printf("%d", sum);
return 0;
}