hdu 2196 Computer(樹形dp)

鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2196
來源:hdu

在這裏插入圖片描述

  題意:輸入 nn 個結點,然後輸入 n1n-1 行,兩個數字 uu ww,表示,ii(第 ii 行) 是 uu 的子結點。求每個結點距離他最遠的距離。(11 號結點爲根結點)
  思路:
  dp[i][0]dp[i][0]:結點 ii 的子樹到 ii 的最長距離
  dp[i][1]dp[i][1]:結點 ii 的子樹到 ii 的次長距離
  dp[i][2]dp[i][2]:從結點 ii 往上走的最長距離
  每個結點的最長和次長距離我們用 dpdp 的方式自下而上的去更新(保證次長和最長分別分佈在左右子樹上),算出 dp[i][0]dp[i][0]dp[i][1]dp[i][1] 後,如果要計算 uu 的上面的最長距離,我們可以發現:
  如果 uu 不在其父親的最長鏈上,那麼距離他最長的距離就是
  max()+max(他父親往上走的最長距離,他父親的子樹的最長距離) + 他們之間的距離
  如果 uu 在其父親的最長鏈上,那麼距離他最長的距離就是
  max()+max(他父親往上走的最長距離,他父親的子樹的次長距離) + 他們之間的距離
  上述語言符號化:
  if(dp[v][0]+w[u][v]==dp[u][0])if(dp[v][0]+w[u][v]==dp[u][0]) 兒子在父親的最長鏈上
  dp[v][2]=max(dp[u][2],dp[u][1])+w[u][v]dp[v][2]=max(dp[u][2],dp[u][1]) + w[u][v]
  elseelsedp[v][2]=max(dp[u][2],dp[u][0])+w[u][v]dp[v][2]=max(dp[u][2],dp[u][0])+w[u][v] 兒子不在父親的最長鏈上

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int Max_n = 1e4 + 10;
int head[Max_n], cnt;
ll dp[Max_n][3];

struct Edge {
    int u, v, w, next;
} edge[Max_n << 1];

void addedge(int u, int v, int w) {
    edge[cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

void dfs1(int u) {
    ll one = 0, two = 0;
    for(int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v;
        dfs1(v);
        ll cost = dp[v][0] + (ll)edge[i].w;
        if(cost >= one) {
            two = one;
            one = cost;
        }
        if(cost < one && cost > two) {
            two = cost;
        }
    }
    dp[u][0] = one;
    dp[u][1] = two;
}

void dfs2(int u) {
    for(int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v;
        if(dp[v][0] + (ll)edge[i].w == dp[u][0])
            dp[v][2] = max(dp[u][2], dp[u][1]) + (ll)edge[i].w;
        else
            dp[v][2] = max(dp[u][2], dp[u][0]) + (ll)edge[i].w;
        dfs2(v);
    }
}

int main() {
    int n;
    while(~scanf("%d", &n)) {
        cnt = 0;
        for(int i = 1; i <= n; i++)
            head[i] = -1;
        for(int i = 2; i <= n; i++) {
            int u, w;
            scanf("%d%d", &u, &w);
            addedge(u, i, w); //i 是 u 的子結點
        }
        memset(dp, 0, sizeof(dp));
        dfs1(1);
        dfs2(1);
        for(int i = 1; i <= n; i++)
            printf("%lld\n", max(dp[i][0], dp[i][2]));
    }
    return 0;
}

/**
* Copyright(c)
* All rights reserved.
* Author : Max_n
* Date : 2019-10-07-21.39.43
* Problem : hdu 2196 Computer
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章