这道题还是比较不容易理解的
主要是多用了一个dfs,多饶了一个弯
这道题符合树形DP的特征,可以把问题转化为一棵树
对于每一个点,计算出以此点为根的子树中的第一长的枝和第二长枝,都存起来
这是一个相当重要的预处理
当图转为树的时候,对于每一个点其最远点有两种情况(两种情况取最优)
1.返回父节点,来寻找最远点
2.直接继续向下找,找到最远点
对于第二种情况,由于向下找,长度必定为其最长枝的长度,预处理中已经找到,只需要在最后比较一下就OK
主要就是看前两种情况:
对于第二种情况,需要找一下可以向上走的最大长度,由于第二次求最远点的dfs中可以从根节点开始计算,向下依次递推
但是需要分情况1.该点在这棵树的最长枝中 2.该点未在这棵树的最长枝中
具体详解在代码中体现
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 11111
struct Edge
{
int v,w,next;
} edge[MAXN<<1];
int NE,head[MAXN];
void addEdge(int u,int v,int w)
{
edge[NE].v=v;
edge[NE].w=w;
edge[NE].next=head[u];
head[u]=NE++;
}
long long d[3][MAXN];
int idx[MAXN];
void dfs0(int u,int fa)//fa表示u的父节点
{
long long mx0=0,mx1=0;//mx0存最大的,mx1存第二大的
for(int i=head[u]; i!=-1; i=edge[i].next)//搜索所有的边
{
int v=edge[i].v;
if(v==fa) continue;
dfs0(v,u);//递归求值
if(mx0<=d[0][v]+edge[i].w) mx1=mx0,mx0=d[0][v]+edge[i].w,idx[u]=v;//idx记录最长路径
else if(mx1<d[0][v]+edge[i].w) mx1=d[0][v]+edge[i].w;
else if(mx1<d[1][v]+edge[i].w) mx1=d[1][v]+edge[i].w;
}
d[0][u]=mx0;//d[0][u]表示以u为跟的树两条最长枝,mx0,mx1
d[1][u]=mx1;//
}
void dfs1(int u,int fa)
{
for(int i=head[u]; i!=-1; i=edge[i].next)//搜索所有的边
{
int v=edge[i].v;
if(v==fa) continue;
if(idx[u]==v) d[2][v]=max(d[1][u]+edge[i].w,d[2][u]+edge[i].w);//如果在最长路径中
else d[2][v]=max(d[0][u]+edge[i].w,d[2][u]+edge[i].w);//
dfs1(v,u);
}
}
int main()
{
int n,a,b;
while(~scanf("%d",&n))
{
NE=0;
memset(head,-1,sizeof(head));
for(int i=2; i<=n; ++i)
{
scanf("%d%d",&a,&b);
addEdge(i,a,b);
addEdge(a,i,b);
}
memset(d,0,sizeof(d));
dfs0(1,1);
dfs1(1,1);
for(int i=1; i<=n; ++i)
{
printf("%lld\n",max(d[0][i],d[2][i]));
}
}
return 0;
}