HDU 2196

题意:有n台电脑,他们之间连着线,之间具有权值,问每一台电脑到哪台电脑的权值最大。

分析:这n台电脑的关系可以构成一棵树,问题即问到叶子结点的最远距离是多少。

   设dp(i,0)表示以i为子树的最远叶子结点距离,dp(i,1)表示以i为子树的次远叶子结点距离,dp(i,2)表示tree(root)-tree(i)的最远距离+dis(root,i),root为i的父节点

           要保存次远距离是因为,i的父节点的最远距离有可能会经过i,所以此时就要选择次远距离的值,而不能选择最远的。

         

#include <bits/stdc++.h>

using namespace std;
const int maxn = 10005;
struct node{
    int v,w;
};

vector<node> com[maxn];
int dp[maxn][3];           //dp[i][0]表示以i为子树的最长距离,dp[i][1]表示以i为子树的次长距离,dp[i][2]表示i的根节点的最长距离加上i和根节点的距离
int visit[maxn];
void dfs1(int u){   //计算以i为子树的最长距离和次长距离
    visit[u] = 1;
    int max1 = 0,max2 = 0;
    for(int i = 0;i < com[u].size();i++){
        int V = com[u][i].v;
        int W = com[u][i].w;
        if(!visit[V]){
            dfs1(V);
            int tmp = dp[V][0] + W;
            if(tmp >= max1){
                max2 = max1;
                max1 = tmp;
            }
            else if(tmp > max2){
                max2 = tmp;
            }
        }
    }
    dp[u][0] = max1;
    dp[u][1] = max2;
}

void dfs2(int u){
    visit[u] = 1;
    for(int i = 0;i < com[u].size();i++){
        int V = com[u][i].v;
        int W = com[u][i].w;
        dp[V][2] = max(dp[u][2],dp[V][0] + W == dp[u][0] ? dp[u][1]:dp[u][0]) + W;
        if(!visit[V])
            dfs2(V);
    }
}
int main(){
    int n;
    int a,b;
    while(scanf("%d",&n) != EOF){
        for(int i = 1;i <= n;i++)
            com[i].clear();
        for(int i = 2;i <= n;i++){
            scanf("%d%d",&a,&b);
            com[a].push_back(node{i,b});
        }
        memset(dp,0,sizeof(dp));
        memset(visit,0,sizeof(visit));
        dfs1(1);
        memset(visit,0,sizeof(visit));
        dfs2(1);
        for(int i = 1;i <= n;i++){
            printf("%d\n",max(dp[i][0],dp[i][2]));
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值