树的直径+证明

概念

树的直径:2点距离最远的路径。

结论

先说结论,对于一颗无根树,首先随便找一个点 u 开始进行搜索,找到离当前点最远的一点 s , 然后从 s 开始搜最远的点 t ,树的直径就为 s - t 。

证明

找到直径,我们只需找到直径2个端点其中的一个,然后找到离当前点最远的点即为另一个端点。
1.首先u在s-t的路径上,很明显是对的,到达u最远的点必为s或t,因为是从u开始搜最远的点的。

2.u不在s-t的路径上,那么从u搜最远的点必然与s-t相交。
在这里插入图片描述
如图,如果u搜到最远的点为T,那么dis(u,t) > dis(u,x) + dis(x,t)
很显然: dis(s,t ) = dis(s,x) + dis(x,t) < dis(s,T) = dis(s,x) + dis(u,x) + dis(u,T)

所以 很容易得出必与直径相交,且搜到的点为另一个端点。

模板

void dfs(int u,int f){
    for(int i = 0;i < sp[u].size();i++){
        int v = sp[u][i].v;
        int w = sp[u][i].w;
        if(v==f)continue;
        dis[v] = dis[u] + w;
        dfs(v,u);
    }
}

模板题

#pragma GCC optimize(2)
#include<iostream>
#include<vector>
using namespace std;
const int man = 2e5+10;

struct node{
    int v,w;
    node(){}
    node(int v,int w){
        this->v = v;
        this->w = w;
    }
};
vector<node>sp[man];
ll dis[man];

void dfs(int u,int f){
    for(int i = 0;i < sp[u].size();i++){
        int v = sp[u][i].v;
        int w = sp[u][i].w;
        if(v==f)continue;
        dis[v] = dis[u] + w;
        dfs(v,u);
    }
}


int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    int n,m;
    cin >> n >> m;
    for(int i = 1;i <= m;i++){
        int u,v,w;
        char c;
        cin >>u >> v >>w >> c;
        sp[u].push_back(node(v,w));
        sp[v].push_back(node(u,w));
    }
    dis[1] = 0;
    dfs(1,0);
    ll max_ans = 0,max_i = 1;
    for(int i = 1;i <= n;i++){
        if(dis[i]>max_ans){
            max_ans = dis[i];
            max_i = i;
        }
    }
    dis[max_i] = 0;
    max_ans = 0;
    dfs(max_i,0);
    for(int i = 1;i <= n;i++){
        max_ans = max(max_ans,dis[i]);
    }
    cout << max_ans <<endl;
    return 0;
}
发布了27 篇原创文章 · 获赞 7 · 访问量 2677

猜你喜欢

转载自blog.csdn.net/weixin_43571920/article/details/104076421