HDOJ 2196

思路:先选定1为树根,进行第一次深搜,很容易求出节点u到其子节点的最长距离和次长距离,求次长距离的目的是如果u的跟节点最长路径经过u则dp的时候就不能取其跟节点的最长距离,应该取其次长距离;然后进行第二次深搜,搜索节点u经过其跟节点的最长距离。如果令dp[u][0],dp[u][1],分别为节点u到子节点的最长,次长距离,dp[u][2]表示节点u经过其跟节点v的最长距离,则状态方程为 dp[u][2] = max(dp[v][2],dp[u][0] + edge[j].w == dp[v][0] ? dp[v][1] : dp[v][0]) + edge[j].w;最后输出答案为max(dp[u][0],dp[u][2]),即某点u的最长距离为其到子节点的最长距离和经过其跟节点的最长距离二者之中的最大者。


#include<iostream>
#include<cstdio>
#include<cstring>
#define MAX 11111
using namespace std;
typedef long long int LL;
typedef struct{
    int to, next, w;
}Node;
Node edge[MAX];
LL head[MAX], dp[MAX][3];
void AddEdge(int u, int v, int w, int i){
    edge[i].to = v;
    edge[i].w = w;
    edge[i].next = head[u];
    head[u] = i;
}
void dfs_to_son(int i){
    LL bigest = 0, biger = 0;
    for(int j = head[i];j != -1;j = edge[j].next){
        int v = edge[j].to;
        dfs_to_son(v);
        LL temp = dp[v][0] + edge[j].w;
        if(bigest <= temp){
            biger = bigest;
            bigest = temp;
        }else if(temp > biger) biger = temp;
    }
    dp[i][0] = bigest;
    dp[i][1] = biger;
}
void dfs_to_father(int i){
    for(int j = head[i];j != -1;j = edge[j].next){
        int v = edge[j].to;
        dp[v][2] = max(dp[i][2], dp[v][0] + edge[j].w == dp[i][0] ? dp[i][1]:dp[i][0]) + edge[j].w;
        dfs_to_father(v);
    }
}
int main(){
    int n, u, w;
    /* freopen("in.c", "r", stdin); */
    while(~scanf("%d", &n)){
        memset(dp, 0, sizeof(dp));
        memset(head, -1, sizeof(head));
        for(int i = 2;i <= n;i ++){
            scanf("%d%d", &u, &w);
            AddEdge(u, i, w, i-1);
        }
        dfs_to_son(1);
        dfs_to_father(1);
        for(int i = 1;i <= n;i ++) printf("%lld\n", max(dp[i][2], dp[i][0]));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值