zoukankan      html  css  js  c++  java
  • 树的直径

    讲课

    一、树的直径

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

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

    树的直径既可以指这个权值,也可以指这个路径 (路径也叫树的最长链)。树的直径有两种三种方法,都是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
  • 相关阅读:
    Java日志框架
    分布式任务并发调度
    并发(三) CountDownLatch
    并发(二)CyclicBarrier
    并发(一) Semaphore
    MySql
    Hash
    由一个序列化框架的更换引发的问题
    navicat 12 激活
    Spring security
  • 原文地址:https://www.cnblogs.com/Aswert/p/13297838.html
Copyright © 2011-2022 走看看