树的直径

概念

树上任意两节点之间最⻓的简单路径即为树的直径。
⼀棵树可以有多条直径,他们的⻓度相等。

性质

若树上所有边的边权均为正,则树的所有直径的中点重合。
结论⼀:不同直径之间⼀定会相交⽽不会相离。
因此,所有直径都是两两相交的。
推论:所有直径的公共边⼀定是连续的。

实现

两次dfs

在⼀棵树上,从任意节点x 开始进⾏⼀次dfs,找到距离x 最远的结点必定为直径的⼀端。
如果存在负边权,上述性质将不再成⽴。因此,两次dfs只适⽤于所有边权全部⾮负的情况。


//从任意结点x开始进行第一次dfs,找到距离x最远的结点y;
//然后再从y结点开始再来一次dfs,找到距离y最远的结点z;
//y~z就是直径的两端

int n;
vector<PII> edges[N];
int d[N], maxd, r;
int pre[N]; // 记录直径所在的路线 

void dfs(int x, int fa){
    pre[x] = fa;
    if(d[x] > maxd) maxd = d[x], r = x;
    for(auto& t : edges[x]){
        int y = t.first, z = t.second;
        if(y == fa) continue;
        d[y] = d[x] + z;
        dfs(y, x);
    }
}

void fun(){
    dfs(1, 0); maxd = d[r] = 0;
    dfs(r, 0);
    for(int i = r; i; i = pre[i]) cout << i << " ";
    cout << endl;
    cout << maxd << endl;
}

局限性:不能求带负边权的直径
优越性:可以求出直径的路径

树形dp

int n;
vector<PII> edges[N];
int f[N], ret;

void dfs(int x, int fa)
{
    for(auto& t : edges[x]){
        int y = t.first, z = t.second;
        if(y == fa) continue;
        dfs(y, x);
        ret = max(ret, f[x] + f[y] + z);
        f[x] = max(f[x], f[y] + z);
    }
}

void fun(){
    dfs(1, 0);
    cout << ret << endl;
}

posted @ 2025-08-29 15:19  xdhking  阅读(29)  评论(0)    收藏  举报