题目链接
题目大意:
给一根无根树,让你求以各个节点为起始点,每个节点到达的最大距离。
输入:输入N表示节点个数,接下来N-1行从2开始,每行输入两个数x1,x2,x1表示第I个节点所连的节点编号,x2表示这条边的权值。
输出:输出每个节点能到达的最大距离。
具体思路:
如图所示计算一个节点所能到达的最大距离包括两部分:
1、以这个节点为根的树所能到达的最大距离,也就是篮圈部分。
2、这个节点父节点为根的树出去蓝色部分所能达到的最大距离+父节点与这个节点相连的边的权值。
这两者取最大值。
所以我们定义
int f[10005][0];表示以x为根节点的和他相连的所有子树的最长距离中的最长值+x根节点到相邻点的距离
int f[10005][1];表示以x为根节点的和他相连的所有子树的最长距离中的次长值+x根节点到相邻点的距离
(不是所有距离中的的次小值)
int f[10005][2];表示通过父节点不经过自身,所能达到的最大距离
f[i][0]和f[i][1]都可以通过一边DFS求出来
注意:
f[i][2]我们需要再DFS一遍,并且分为两种情况分为两种情况:
1、y节点是经过父亲节点f[x][0]的路径上,这时f[y][2]=max(f[x][1]+w, f[x][2]+w)。
2、y节点不经过父亲节点f[x][0]的路径上,这时f[y][2]=max(f[x][0]+w, f[x][2]+w)。
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
struct ty{
int to;
int weight;
};
vector<ty> g[10005];
int f[10005][3];
int r[10005];
void dfs1(int fa,int x){
int len=g[x].size();
for(int i=0;i<len;i++){
if(g[x][i].to==fa) continue;
int w=g[x][i].weight;
dfs1(x,g[x][i].to);
int temp1=f[g[x][i].to][0];
//int temp2=f[g[x][i].to][1];
if(temp1+w>=f[x][0]){
r[x]=g[x][i].to;
f[x][1]=f[x][0];
f[x][0]=temp1+w;
//if(temp2+w>f[x][1]){(这一步不能要,原因我图片上已经写了)
//f[x][1]=temp2+w;
//}
}
else if(temp1+w>=f[x][1]){
f[x][1]=temp1+w;
}
}
return ;
}
void dfs2(int fa,int x){
int len=g[x].size();
for(int i=0;i<len;i++){
int v=g[x][i].to;
int w=g[x][i].weight;
if(v==fa) continue;
if(r[x]==v){
f[v][2]=max(f[x][1]+w,f[x][2]+w);
}
else{
f[v][2]=max(f[x][0]+w,f[x][2]+w);
}
dfs2(x,v);
}
return ;
}
int main(){
while(~scanf("%d",&n)){
memset(f,0,sizeof(f));
memset(r,0,sizeof(r));
for(int i=0;i<=10001;i++) g[i].clear();
for(int i=2;i<=n;i++){
int y,w;
cin>>y>>w;
ty a;
a.to=y;
a.weight=w;
g[i].push_back(a);
a.to=i;
a.weight=w;
g[y].push_back(a);
}
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=n;i++){
cout<<max(f[i][0],f[i][2])<<endl;
}
}
return 0;
}
京公网安备 11010502036488号