HDU 2196 Computer(树形DP)

题目链接:

2196 Computer

思路:

1.对于每一个结点ii,我们需要计算三个值:
dp[i][0]:dp[i][0]:ii为根的子树里,ii往下能达到的最大长度;
dp[i][1]:dp[i][1]:ii为根的子树里,ii往下能达到的次大长度;
dp[i][2]:dp[i][2]:结点ii往上走,能达到的最长长度;
ii能达到的最远距离就是max(dp[i][0],dp[i][2]))max(dp[i][0],dp[i][2]))
其中dp[i][1]dp[i][1]是为了辅助计算出dp[i][2]dp[i][2]
2.前两个值我们可以通过一次DFS、从底部往上计算得出;
第三个值我们从上到下用DFS计算;假设现在父结点是nownow、儿子结点是sonsonnownow往下走能达到最远的那一条路可能经过sonson、也可能不经过sonson
costcostnownowsonson的花费
如果经过sonson,判断条件是cost+dp[son.id][0]==dp[now][0]cost+dp[son.id][0]==dp[now][0],此时sonson往上走的最长路径是max{nowmax{now往下、往次长路径走(即nownow需要往下走最长、但不能经过sonson),nownow往上走}}
如果不经过sonson,那就是max{nowmax{now往下、往最长路径走,nownow往上走}}

代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=1e4+5;
struct node{int id,val;};
vector<node> tree[maxn];
int n,dp[maxn][3];
void dfs1(int now){
    dp[now][0]=dp[now][1]=0;
    for(node& son:tree[now]){
        dfs1(son.id);
        int val=dp[son.id][0]+son.val;
        if(val>=dp[now][0]) dp[now][1]=dp[now][0],dp[now][0]=val;
        else if(val>dp[now][1]) dp[now][1]=val;
    }
}
void dfs2(int now){
    for(node& son:tree[now]){
        if(son.val+dp[son.id][0]==dp[now][0]){
            dp[son.id][2]=max(dp[now][1],dp[now][2])+son.val;
        }else{
            dp[son.id][2]=max(dp[now][0],dp[now][2])+son.val;
        }
        dfs2(son.id);
    }
}
void solve(){
    dfs1(1); dfs2(1);
    for(int i=1;i<=n;i++){
        printf("%d
",max(dp[i][0],dp[i][2]));
        tree[i].clear();
    }
}
int main(){
//    freopen("Sakura.txt","r",stdin);
    while(~scanf("%d",&n)){
        for(int i=2;i<=n;i++){
            int id,val; scanf("%d%d",&id,&val);
            tree[id].push_back(node{i,val});
        }
        solve();
    }
    return 0;
}

原文地址:https://www.cnblogs.com/yuhan-blog/p/12308720.html