HDU 2196 Computer(求树上每个点的最长距离)

 

题意:

这题想了挺久的, 参考了kuangbin大神的代码:https://www.cnblogs.com/kuangbin/archive/2012/08/28/2659915.html

给出树上边的长度, 求出每一个点的最长距离(就是求这个点到某一个叶子结点的距离, 这个距离最长)。

分析:

结点u的最长路径, 其实就是max( u到子树叶子的最长路径,  u到父亲的距离 + 父亲子树的最长路径).

注意, 因为父亲子树的最长路径可能会经过u, 这样这个状态就不能用 u到父亲的距离 + 父亲子树的最长路径表示。

所以记录每个节点的最长路和次长路。

用两次dfs求解。

第一次dfs求出每个点只看子树的最长距离和次长距离。(只关注结点本身)

第二次dfs求出每个孩子结点的最长距离(答案)。(关注结点的孩子)

松弛条件可以看代码。

#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;

const int maxn = 12000 + 7;
const int inf = 1e9 + 7;
int Max[maxn];// 最大距离
int sMax[maxn];// 次大距离
int Id[maxn];// 最大距离对应序号
int sId[maxn];// 次大距离对应序号
struct Edge {
    int v, d;
};
vector<Edge> G[maxn];
int N;
void init() {
    for(int i = 0; i < maxn; i ++) {
        G[i].clear();
    }
}
void dfs1(int u, int pre) {//更新u本身
    Max[u] = sMax[u] = 0;
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].v, d = G[u][i].d;
        if(v == pre)
            continue; //不经过父亲, 只搜索子树
        dfs1(v, u); //一直搜到叶子再回溯, 因为是根据孩子的Max更新自己的Max
        if(sMax[u] < Max[v] + d) { //如果u的次长距离 < 到v的距离  + v的最大距离
            //更新距离
            sMax[u] = Max[v] + d;
            sId[u] = v;
            if(sMax[u] > Max[u]) { //如果次长距离大于最长距离, 交换二者位置
                swap(sMax[u], Max[u]);
                swap(sId[u], Id[u]);
            }
        }
    }
}
int dfs2(int u, int pre) {//更新u的孩子
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].v, d = G[u][i].d;
        if(v == pre)
            continue; //同样不经过父亲
        if(v == Id[u]) { //如果v在u的最长路径上
            if(sMax[u] + d > sMax[v]) { //看看u的次长路 + d 是否> v的次长路
                sMax[v] = sMax[u] + d;
                sId[v] = u;
                if(sMax[v] > Max[v]) { //如果次长距离大于最长距离, 交换二者位置
                    swap(sMax[v], Max[v]);
                    swap(sId[v], Id[v]);
                }
            }
        } else { // v不在u的最长路径上
            if(d + Max[u] > sMax[v]) { //试着更新v
                sMax[v] = d + Max[u];
                sId[v] = u;
                if(sMax[v] > Max[v]) { //如果次长距离大于最长距离, 交换二者位置
                    swap(sMax[v], Max[v]);
                    swap(sId[v], Id[v]);
                }
            }
        }
        dfs2(v, u);
    }
}
int main() {
    while(cin >> N) {
        init();
        for(int i = 2 ; i <= N; i++) {
            int u, v, d;
            cin >> v >> d;
            G[i].push_back((Edge){v,d});
            G[v].push_back((Edge){i,d});
        }
        dfs1(1, -1);

        dfs2(1, -1);

        for(int i = 1; i <= N; i++) {
            cout << Max[i] << "\n";
        }
    }
    return 0;
}

 

posted @ 2018-06-08 21:04  Neord  阅读(121)  评论(0编辑  收藏  举报