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 

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

vector 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;
}


你可能感兴趣的:(树形dp)