树的直径

讲课

一、树的直径

树上两点的距离:从树上一点到另一点所经过的权值

当树上两点距离最大时,就称作树的直径

树的直径既可以指这个权值,也可以指这个路径 (路径也叫树的最长链)。树的直径有两种三种方法,都是O(n)

最笨的方法就是对每一个结点进行 BFS,因为 BFS 有这个性质:BFS 生成的

广度优先树的每一个结点到达根结点的路径总是最短路。这样,把每一个结点 BFS

一遍就会生成一个该结点到达的最远结点。按照定义取出最长的路径即可。由于 BFS 时间复杂度是 O(N),这个方法的时间复杂度是O(N^2)。

1,两次BFS或dfs

贪心求直径的方法是任意找一个点为根,dfs整棵树找到距离他最远的点x,再以这个点x为根求出距离它最远的点y,(x,y)即为直径。(注意:这种方法只能求非负边权)

定理:在一个连通无向无环图中,以任意结点出发所能到达的最远结点,一定是该图直径的端点之一。

证明:假设这条直径是δ(s,t)。

分两种情况:

1.当出发结点 y 在δ(s,t)时,假设到达的最远结点 z 不是 s,t 中的任一个。这时将δ(y,z)与不与之重合的δ(y,s)拼接,可以得到一条更长的直径,与前提矛盾。

2.当出发结点 y 不在δ(s,t)上时,分两种情况:

1). 当 y 到达的最远结点 z 横穿δ(s,t)时,记与之相交的结点为 x。此时有δ(y,z)=δ(y,x)+δ(x,z)。而此时δ(y,z)>δ(y,t),故可得δ(x,z)>δ(x,t)。该假设不成立。

2).当 y 到达的最远结点 z 与δ(s,t)不相交时,当 y 到达的最远结点 z 与δ(s,t)不相交时,记 y 到 t 的最短路首先与δ(s,t)相交的结点是 x。由假设δ(y,z)>δ(y,x)+δ(x,t)。而δ(y,z)+δ(y,x)+δ(x,s)又可以形成δ(z,s)可知不成立

所以定理成立

 

1、直径两端点一定是两个叶子节点

2、距离任意点最远的点一定是直径的一个端点,这个基于贪心求直径方法的正确性可以得出

3、对于两棵树,如果第一棵树直径两端点为(u,v),第二棵树直径两端点为(x,y),用一条边将两棵树连接,那么新树的直径一定是u,v,x,y,中的两个点

证明:如果新树直径不是原来两棵树中一棵的直径,那么新直径一定经过两棵树的连接边,新直径在原来每棵树中的部分一定是距离连接点最远的点,即一定是原树直径的一个端点。

4、对于一棵树,如果在一个点的上接一个叶子节点,那么最多会改变直径的一个端点 证明:假设在x下面接一个点y,直径变成了(u,x),原树直径为(a,b),那么dis(u,x)>dis(a,b),dis(u,x)=dis(u,y)+1,dis(u,x)=dis(u,y)+1,即dis(u,y)+1>dis(a,b),如果dis(u,y)<dis(a,b),那么显然不成立;如果dis(u,y)=dis(a,b),那么(u,y)也是原树的直径,符合上述结论。

5、若一棵树存在多条直径,那么这些直径交于一点且交点是这些直径的中点

dfs

int dfs(int u,int fa){
    if(sum<dis[u]){
        sum=dis[u];
        t=u;
    }
    for(int i=head[u];i;i=e[i].nxt){
        int to=e[i].v;
        if(to!=fa){
            pre[to]=i;
            dis[to]=dis[u]+e[i].w;
            dfs(to,u);
        }
    }
}
View Code

bfs

void bfs(int x){
    memset(dis,0,sizeof dis);
    memset(vis,0,sizeof vis);
    queue<int>q;
    q.push(x);
    vis[x]=1;
    while(q.size()){
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=e[i].nxt){
            int to=e[i].v;
            if(!vis[to]){
                pre[to]=now;
                dis[to]=dis[now]+1;
                vis[to]=1;
                q.push(to);
            }
        }
    }
    t=0;
    for(int i=1;i<=n;i++){
        if(dis[i]>t){
            t=dis[i],f[0]=i;
        }
    }
}
View Code

dp

int dp(int u){
    vis[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int to=e[i].v;
        if(vis[to])continue;
        dp(to);
        sum=max(sum,f[u]+f[to]+e[i].w);
        f[u]=max(f[to]+e[i].w,f[u]);
    }
}
View Code

 

posted @ 2020-07-14 10:50  Aswert  阅读(592)  评论(0编辑  收藏  举报