HDU 2196 经典树形DP

大体思路是将一个无根数转化为有根树,再深搜两次,第一次将每个子树的根距其叶子的最远距离求出来(自下而上),第二次求每个节点到其他结点的最远距离(自上而下),但因为在第二次深搜时可能会碰到一个结点的父节点的最远距离经过它,所以我们需要保存一个最长距离和一个次长距离

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;

#define MAXN 10010

int dp[MAXN][2];
int len[MAXN];
vector<int> tree[MAXN];

void first_dfs(int src){
    int tree_len = tree[src].size();
    for(int i = 0;i<tree_len;++i){
        int s = tree[src][i];
        first_dfs(s);
        int v = len[s]+dp[s][0];
        dp[src][1] = max(dp[src][1],v > dp[src][0]?dp[src][0]:v);
        dp[src][0] = max(dp[src][0],v);
    }
}

void second_dfs(int src){
    int tree_len = tree[src].size();
    for(int i = 0;i < tree_len;++i){
        int s = tree[src][i];
        int v = (dp[s][0]+len[s] == dp[src][0]?dp[src][1]:dp[src][0])+ len[s];
        dp[s][1] = max(dp[s][1],v > dp[s][0]?dp[s][0]:v);
        dp[s][0] = max(dp[s][0],v);
        second_dfs(s);
    }
}

int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i = 1;i<=n;++i){
                tree[i].clear();
        }
        memset(dp,0,sizeof(dp));
        int a;
        for(int i = 2;i<=n;++i){
            scanf("%d%d",&a,&len[i]);
            tree[a].push_back(i);
        }
        first_dfs(1);
        second_dfs(1);
        for(int i = 1;i<=n;++i){
            printf("%d\n",dp[i][0]);
        }
    }
    return 0;
}
posted @ 2017-04-23 17:36  殷恪祎  阅读(123)  评论(0编辑  收藏  举报