acwing 1073 树的中心 (树形DP)

题面

在这里插入图片描述

题解

我们要枚举每个点到其它点的最远距离,那么就会有两种情况,向上走或者是向下走

假设我们枚举u点,向下走 dfs_down(u) 更新当前节点向下走,叶子节点不需要更新
在这里插入图片描述
d1[u] 表示 u点向下的最长路径,d2[u] 表示 u 点向下的次长路径 ,p1[u] 表示 u 的向下最长路径经过的子节点 。 那么我们只要每次枚举u节点的儿子,然后更新即可

向上走:dfs_up 传入 u 节点, 我们更新它的每一个儿子(因为开始传入的u是根节点不需要向上更新)
在这里插入图片描述
对于u的儿子 j ,第一步肯定是向上走,距离是 w[i] , 那么接接下来就有两种方式,继续向上或向下 ,如果是从u节点向下的话,j是最长路径上的一个点,我们就选择次长的路径,如果j不是最长路径上的点,我们就选择最长路 ,然后向上,向下取一个最大即可

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>


using namespace std;
const int N = 1e4 + 10;
const int INF = 0x3f3f3f3f;

int n;
int h[N], e[N * 2], w[N * 2], ne[N * 2], idx;
int d1[N], d2[N], p1[N], up[N];  //p1数组标记这个节点的最长路径要经过哪个子节点
int is[N];   //标记是否为叶子节点

void add(int a, int b, int c) {
    
    
    e[idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx++;
}


//向下求最长
int dfs_down(int u, int father) {
    
    
    d1[u] = d2[u] = -INF;
    for (int i = h[u]; i != -1; i = ne[i]) {
    
    
        int j = e[i];
        if (j == father) continue;
        int d = dfs_down(j, u) + w[i];   //遍历求每个儿子的最长长度
        if (d > d1[u]) d2[u] = d1[u], d1[u] = d, p1[u] = j;   //更新这个节点的最长和次长
        else if (d > d2[u]) d2[u] = d;
    }

    if (d1[u] == -INF) {
    
      //说明是叶子节点
        d1[u] = d2[u] = 0;
        is[u] = true;
    }

    return d1[u];
}


//向上求最长
int dfs_up(int u, int father) {
    
    

    for (int i = h[u]; i != -1; i = ne[i]) {
    
    
        int j = e[i];
        if (j == father) continue;
        //u的最长经过点j,那么就要找次边
        if (p1[u] == j) up[j] = max(up[u], d2[u]) + w[i];
        else up[j] = max(up[u], d1[u]) + w[i];
        dfs_up(j, u);
    }
}

int main() {
    
    

    memset(h, -1, sizeof h);

    cin >> n;
    for (int i = 1; i < n; i++) {
    
    
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c), add(b, a, c);
    }

    dfs_down(1, -1);
    dfs_up(1, -1);

    int res = d1[1];
    for (int i = 2; i <= n; i++) {
    
    
        if (is[i]) res = min(res, up[i]);   //根节点只能向上找
        else res = min(res, max(d1[i], up[i]));
    }

    cout << res << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44791484/article/details/114728262