1. 程式人生 > >HDU 2196 Computer (樹上最遠距離)

HDU 2196 Computer (樹上最遠距離)

題意:給你一棵樹,之後讓你求出這個樹上每個點的距離的最大值。

思路:首先怎樣求一個樹上一個點到另外一個點的最遠距離?其實就是一個點往父親方向的最大值+往兒子方向的最大值,可知這些東西肯定都是單向的,因為你要麼往兒子方向走你就只能往兒子方向走,不能再回去往父親方向走,那麼我們就可以設:

f[u]表示的是你往兒子方向的最大值,

g[u]表示的是你往父親方向的最大值,

p[u]表示的是u的父親,那麼就有:

f[u] = max(f[v] + w(u,v))  // v 是 u 的兒子

g[u] = w(p[u],u) + max(g[p[u]] , w(u,v) + f[u])   // v 是 u的兄弟。

解釋一下g[u]這個dp方程首先就是我們遍歷u的父親節點,最大值是怎樣轉移的?有兩種情況1:從u的父親哪裡轉移,2從u的兄弟哪裡拐過來的,之後求一個最大值就好了

程式碼:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 10;
vector<pair<int,int> >G[maxn];
int p[maxn] , f[maxn] , g[maxn];
void dfs1(int u,int fa)
{
    p[u] = fa;
    for(int i = 0 ; i < G[u].size() ; i ++)
    {
        int v = G[u][i].first , w = G[u][i].second;
        if(v == fa) continue;
        dfs1(v,u);
        f[u] = max(f[v] + w , f[u]);
    }
}
void dfs2(int u , int fa)
{
    int t = 0;
    g[u] = g[fa];
    for(auto i : G[fa])
    {
        int v = i.first , w = i.second;
        if(v == p[fa]) continue;
        if(v == u) t = w;
        else g[u] = max(g[u] , f[v] + w);
    }
    g[u] += t;
    for(auto i : G[u])
    {
        int v = i.first;
        if(v == fa) continue;
        dfs2(v,u);
    }
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        for(int i = 1 ; i <= n ;i ++) G[i].clear();
        int v , w;
        for(int u = 2 ; u <= n ; u++)
        {
            scanf("%d%d",&v,&w);
            G[u].push_back(make_pair(v,w));
            G[v].push_back(make_pair(u,w));
        }
        dfs1(1,0);
        dfs2(1,0);
        for(int i = 1 ; i <= n ; i++) printf("%d\n",max(f[i],g[i]));