问题描述
请求出权值非负的无向树T的直径。我们将树的最远结点之间的距离称为树的直径。
输入:
输入按照以下形式给出
n
n
n
s
1
s_1
s1
t
1
t_1
t1
w
1
w_1
w1
s
2
s_2
s2
t
2
t_2
t2
w
2
w_2
w2
…
s
n
−
1
s_{n-1}
sn−1
t
n
−
1
t_{n-1}
tn−1
w
n
−
1
w_{n-1}
wn−1
第1行输入表示树结点数的整数n。树的各结点编号分别为0到n-1。
接下来n-1行输入树的边。
s
i
s_i
si、
t
i
t_i
ti表示第 i 条边的两个端点,
w
i
w_i
wi表示第 i 条边的权值(距离)。
输出:
输出直径,占1行。
限制:
1 ≤ n ≤ 100000
0 ≤
w
i
w_i
wi ≤ 1000
输入示例
第一组
4
0 1 2
1 2 1
1 3 3
第二组
4
0 1 1
1 2 2
2 3 4
输出示例
第一组
5
第二组
7
讲解
通过下述算法可以相对简单地求解树的直径
1.任选一结点s,求到s最远的结点x。
2.求到x最远的结点y。
3.报告结点x与y的距离,即树的直径。
该算法的严密证明过于繁琐,所以只介绍一种方法来验证其合理性。设结点a到结点b的距离为d(a, b)。
首先,根据树的性质可知如下内容:
x、y均为叶结点。如果两个结点的距离是直径,那么它们必然都是叶结点。
两个不同结点之间仅存在一条路径。
各权边值非负。
现假设另外两个结点u、v的距离d(u, v)为树的直径,而上面的算法得出的直径仍为d(x, y)。
AC代码如下
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
#define MAX 100000
#define INFTY (1<<30)
class Edge{
public:
int t, w;
Edge(){}
Edge(int t, int w): t(t), w(w) {}
};
vector<Edge> G[MAX];
int n, d[MAX];
bool vis[MAX];
int cnt;
void bfs(int s){
for(int i = 0; i < n; i++) d[i] = INFTY;
queue<int> Q;
Q.push(s);
d[s] = 0;
int u;
while(!Q.empty() ){
u = Q.front(); Q.pop();
for(int i = 0; i < G[u].size(); i++){
Edge e = G[u][i];
if(d[e.t] == INFTY){
d[e.t] = d[u] + e.w;
Q.push(e.t);
}
}
}
}
void solve(){
//从任选的结点s出发,选择距离s最远的结点tgt
bfs(0);
int maxv = 0;
int tgt = 0;
for(int i = 0; i < n; i++){
if(d[i] == INFTY) continue;
if(maxv < d[i]){
maxv = d[i];
tgt = i;
}
}
//从tgt出发,求结点tgt到最远节点的距离maxv
bfs(tgt);
maxv = 0;
for(int i = 0; i < n; i++){
if(d[i] == INFTY) continue;
maxv = max(maxv, d[i]);
}
cout<<maxv<<endl;
}
int main(){
int s, t, w;
cin>>n;
for(int i = 0; i < n-1; i++){
cin>>s>>t>>w;
G[s].push_back(Edge(t, w));
G[t].push_back(Edge(s, w));
}
solve();
}