hdu 2196 树形dp

题意: 给你n太台电脑 及 相邻之间的 距离 让你求出 每台电脑的离它最远的电脑的离;

思路:树形dp,题意给出一棵树,求离每个节点最远的点的距离, 两种情况1,以该节点s作为根节点的子树中的离该节点最长距离x。2,其父树中离该节点的最长距离y。答案就是max(x, y);

需要注意的是:父树中的最长距离有可能经过s点, 这时候就要选父树中次长的路径(求第一种时顺便求出)

ps:建图时是双向边  不明白在纸上画图走一遍样例

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <queue>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#define N 10005<<1
#define INF 10000000
#define LL long long
#define eps 10E-9
#define mem(a)  memset(a,0,sizeof(a))
#define mem1(a)  memset(a,-1,sizeof(a))
#define w(a)   while(a)
#define s(a)   scanf("%d",&a)
#define ss(a,b)   scanf("%d%d",&a,&b)
#define sss(a,b,c)   scanf("%d%d%d",&a,&b,&c)
using namespace std;
int dp[N][3];//设dp[i][1]、dp[i][0]第i节点的子树方向最长距离、次长距离 ,设dp[i][2]为第i节点的父树方向最长距离
int fnext[N];//与第i条边同起点的下条边的位置
int head[N];//以i为起点的第一条边的位置
int edge[N];//第i条边的终点
int cost[N];//第i条边的长度
int vis[N];//优化 用不用都行
void add(int i, int a, int b, int c){
     edge[i] = b;
     fnext[i] = head[a];
     head[a] = i;
     cost[i] = c;
}
void tree_dp1(int a, int b){
     for(int i=head[a]; i!=-1; i=fnext[i]){
        int k = edge[i];
        if( k!= b){
            tree_dp1(k, a);
            if(dp[a][0] < cost[i] + dp[k][0]){
                    dp[a][1] = dp[a][0];
                    dp[a][0] = cost[i] + dp[k][0];
               }
            else if(dp[a][1] < cost[i] + dp[k][0]) dp[a][1] = cost[i] +  dp[k][0];
        }
     }
}
void tree_dp2(int a, int b){
     int len = 0;
     for(int i=head[a]; i!=-1; i=fnext[i]){
        if(edge[i] == b){
           len = cost[i]; break;
        }
     }
     if(b != -1 && !vis[a]){
        dp[a][2] = dp[b][2];
        if(dp[a][0] + len == dp[b][0] && dp[b][1] > dp[a][2]) dp[a][2] = dp[b][1];
        if(dp[a][0] + len != dp[b][0] && dp[b][0] > dp[a][2]) dp[a][2] = dp[b][0];
        dp[a][2] += len ;
        vis[a] = 1;
     }
     for(int i=head[a]; i!=-1; i=fnext[i]){
        if(edge[i] !=b ) tree_dp2(edge[i], a);
     }
}
int main(){
   int n, j, i, a, b;
   w(~s(n)){
         mem(vis);
         mem(dp);
         mem1(fnext);
         mem1(head);
         for(i=2, j=1; i<=n; i++){
            ss(a, b);
            add(j++, i, a, b);
            add(j++, a, i, b);
         }
         tree_dp1(1, -1);//求子树最长距离
         tree_dp2(1, -1);//求父树最长距离
         for(int i=1; i<=n; i++)    printf("%d\n",max(dp[i][0],dp[i][2]));
   }
   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值