题目分析
这道题好难想呀!!看了别人的题解继续想还是想不明白,主要是自己的一个点没有过来,题解是先求出每个节点到叶子节点的最长路以及次长路用dp[u][0]和dp[u][1]表示,然后再用一遍dfs求每个节点到经过其父亲节点出发的另一条最长路,状态转移方程是这样的,如果这个节点在其父亲节点的最长路上,那么这个节点经过其父亲节点的最长路我们用dp[son][2]表示,则
dp[u][2]=max(dp[fa][1]+len,dp[fa][2]+len)len表示子节点到父亲节点的距离,如果不经过父亲节点的最长路,那么dp[u][2]=max(dp[fa][0]+len,dp[fa][2]+len),这个状态转移方程很好理解,但是我一直不明白的是,如果其父亲的父亲的节点经过此节点那么是不是算错了,我感觉这个状态转移就不是正确的,但是后来分析了一下,如果一个点的不在其父亲节点的最长路上,那么其不可能在其父亲的父亲的节点的最长路长(树本身的性质决定的,很容易想明白),因此我的想法是不可能发生的。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 10005;
int head[maxn],dp[maxn][3],tot;
struct Edge{
int to,w,next;
}e[maxn<<1];
void addedge(int from, int to, int w){
e[tot].to = to;
e[tot].w = w;
e[tot].next = head[from];
head[from] = tot++;
}
void dfs1(int u,int fa){ //求每个节点到叶子节点的最长路和次长路
for(int i = head[u]; i != -1; i = e[i].next){
int v = e[i].to;
if(v != fa){
dfs1(v, u);
if(dp[u][0] < e[i].w + dp[v][0]){
dp[u][1] = dp[u][0];
dp[u][0] = e[i].w + dp[v][0];
}
else if(dp[u][1] < e[i].w + dp[v][0])
dp[u][1] = e[i].w + dp[v][0];
}
}
}
void dfs2(int u,int fa){
int len;
for(int i = head[u]; i != -1; i = e[i].next) //找到父亲节点
if(e[i].to == fa){
len = e[i].w;
break;
}
if(fa != 0){ //如果不是根节点,根节点肯定是最长路最大(因为没有父节点)
if(dp[u][0] + len == dp[fa][0]){ //如果孩子节点在父亲节点的最长路上
if(dp[fa][1] > dp[fa][2])
dp[u][2] = dp[fa][1] + len;
else
dp[u][2] = dp[fa][2] + len;
}
else{
if(dp[fa][0] > dp[fa][2])
dp[u][2] = dp[fa][0] + len;
else
dp[u][2] = dp[fa][2] + len;
}
}
for(int i = head[u]; i != -1; i = e[i].next)
if(e[i].to != fa) dfs2(e[i].to, u);
}
void init(){
memset(head, -1, sizeof(head));
memset(dp, 0, sizeof(dp));
tot = 0;
}
int main(){
int N;
while(scanf("%d", &N) != EOF){
init();
int to,w;
for(int from = 2; from <= N; from++){
scanf("%d%d", &to, &w);
addedge(from, to, w);
addedge(to, from, w);
}
dfs1(1, 0);
dfs2(1, 0);
for(int i = 1; i <= N; i++)
printf("%d\n", max(dp[i][0], dp[i][2]));
}
return 0;
}