思路:以2号点为例:当求2号点的最大值时:
max[2] = e[2,i] + max[i].
①如果i的最大值max[i]经过2好点时,则不成立,所以此时max[i]为i号点最远距离的次大值。
②当i的最大值max[i]不经过2好点时,成立。
所以此时需要两边dfs,第一遍用子节点去更新父节点,第二遍用父节点更新子节点。
第一遍dfs:求出来所有结点不经过其父节点的最大值
int d1[N],d2[N],p1[N];
//d1[i]表示结点i的最大距离,p1[i]表示结点i的最大距离第一个经过的子节点
//d2[i]表示结点i的次大距离
//第一遍dfs求出所有不经过其父节点的最大距离
//返回x结点不经过父节点f的最大距离
int dfs1(int x,int f){
//x表示当前结点,f表示当前结点的父节点
int i;
d1[x] = -inf;
d2[x] = -inf;
for(i = h[x];i!=-1;i = e[i].ne){
int v = e[i].v,w = e[i].w;
if(v == f) continue;
int t = dfs1(v,x) + w;
if(t>d1[x]){
p1[x] = v;
d2[x] = d1[x];
d1[x] = t;
}else if(t>d2[x]){
d2[x] = t;
}
}
//如果该点的最大距离没有被更新过,则为叶子结点,距离为0
if(d1[x] == -inf) d1[x] = 0;
if(d2[x] == -inf) d2[x] = 0;
return d1[x];
}
问题:如何用父节点更新子节点?
在第一遍dfs时记录父节点的最远值和次远值以及最远路径最开始经过的点,对于最远路径经过的子节点,其max[子节点] = e[子节点,父节点]+父节点的次远值,与当第一遍求得的子节点的最远值取最大。
第二遍dfs:求出所有结点经过其父节点的最大值
int up[N];
//up[i]表示经过其父节点的最大距离
//第二遍dfs求出所有点经过其父节点的最大距离
void dfs2(int x,int f){
int i;
for(i = h[x];i!=-1;i=e[i].ne){
int v = e[i].v,w = e[i].w;
if(v == f) continue;
if(p1[x] != v){
//如果x的最大值经过子节点v,则更新up[v]
up[v] = max(up[x]+w,d1[x]+w);
}else{
up[v] = max(up[x]+w,d2[x]+w);
}
dfs2(v,x);
}
return;
}
ac代码:
#include<iostream>
#include<cstring>
using namespace std;
const int N = 10005;
const int inf = 0x3f3f3f3f;
struct edge{
int v,w,ne;
}e[2*N];
int h[N],idx;
void add(int a,int b,int w){
e[idx].v = b;
e[idx].w = w;
e[idx].ne = h[a];
h[a] = idx++;
}
int n;
int d1[N],d2[N],p1[N];
//d1[i]表示结点i的最大距离,p1[i]表示结点i的最大距离第一个经过的子节点
//d2[i]表示结点i的次大距离
//第一遍dfs求出所有不经过其父节点的最大距离
//返回x结点不经过父节点f的最大距离
int dfs1(int x,int f){
//x表示当前结点,f表示当前结点的父节点
int i;
d1[x] = -inf;
d2[x] = -inf;
for(i = h[x];i!=-1;i = e[i].ne){
int v = e[i].v,w = e[i].w;
if(v == f) continue;
int t = dfs1(v,x) + w;
if(t>d1[x]){
p1[x] = v;
d2[x] = d1[x];
d1[x] = t;
}else if(t>d2[x]){
d2[x] = t;
}
}
//如果该点的最大距离没有被更新过,则为叶子结点,距离为0
if(d1[x] == -inf) d1[x] = 0;
if(d2[x] == -inf) d2[x] = 0;
return d1[x];
}
int up[N];
//up[i]表示经过其父节点的最大距离
//第二遍dfs求出所有点经过其父节点的最大距离
void dfs2(int x,int f){
int i;
for(i = h[x];i!=-1;i=e[i].ne){
int v = e[i].v,w = e[i].w;
if(v == f) continue;
if(p1[x] != v){
//如果x的最大值经过子节点v,则更新up[v]
up[v] = max(up[x]+w,d1[x]+w);
}else{
up[v] = max(up[x]+w,d2[x]+w);
}
dfs2(v,x);
}
return;
}
int main(){
int i,j;
cin>>n;
memset(h,-1,sizeof h);
for(i =1;i<n;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
dfs1(1,-1);
dfs2(1,-1);
int ans = inf;
int res;
for(i = 1;i<=n;i++){
res = max(d1[i],up[i]);
ans = min(ans,res);
}
cout<<ans;
return 0;
}
大佬,我有个问题想不明白,就是在用父节点更新子节点的信息的时候,怎么保证它一定是往上走的