HDU 2196 Computer(树形DP)

题目分析

这道题好难想呀!!看了别人的题解继续想还是想不明白,主要是自己的一个点没有过来,题解是先求出每个节点到叶子节点的最长路以及次长路用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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值