zoukankan      html  css  js  c++  java
  • LCA(最近公共祖先)问题

    问题描述

    在一棵树中,如果某个节点z是节点x的祖先(即节点z深度<节点x),也是y的祖先。那么称节点z是x与y的公共祖先。

    那顾名思义,所谓最近公共祖先,就是对于x和y来说距离之和最近的公共祖先。

    解法一:向上标记法

    除非你发了高烧啥都不会打,否则换方法

    从x节点向上走到根节点,把所有经过的节点标记。

    从y节点向上走,第一次遇到被标记过的节点的时候,该节点为所求点。

    每次询问,最坏复杂度为O(n)

    解法二:树上倍增法

    不温不火,很适合考场的时候打啊…

    首先理解倍增算法。类似于动态规划思想

    复杂度O((n+m)log n)

    倍增预处理

    设F[x,k]表示x的2k辈祖先。也就是,x向上跳2k所到达的节点。如果跳到了一个压根不存在的节点,我们让他的值为0。

    显然根据定义,可以得出F[x,0]就是x的父节点。

    为了不少跳,求出k的范围应当属于[1,logn]。在c++中,应写为

    t=(int)log(n)/log(2)+1

    接下来就有转移方程:

    F[x,k]=F[F[x,k-1],k-1] ,因为 2k-1+2k-1=2* 2k-1=2k

    预计需要的时间复杂度O(n logn)

    void bfs(){
        q.push(1);
        d[1]=1;
        while(q.size()){
            int x=q.front();q.pop();
            for(int i=Head[x];i;i=Next[i]){
                int y=End[i];
                if(d[y]) continue;
                d[y]=d[x]+1;
                f[y][0]=x;
                for(int j=1;j<=t;j++){
                    f[y][j]=f[f[y][j-1]][j-1];
                }
                q.push(y);
            }
        }
    }

    跳跃式处理LCA 

    由上面的预处理,我们得到了已经初始化的D(深度)数组和F(倍增)数组

    我们假定D[x]>=D[y]  (否则你就交换一下嘛)

    1.让x往上跳,先跳到和y一样高再说

      怎么实现呢?枚举。枚举上跳步数。枚举jump=2logn一直枚举到20。为什么要倒着呢?因为要尽可能跳的次数少一点降低复杂度。

      检查即将上跳到的节点是否比y要低一点。如果是就完成上跳,即让x=F[x,jump]

    2.如果发现仅仅完成第一步就有了x==y(x跳到y脸上去了),说明y本来就是x的祖先,那么LCA就等于y。

    3.让x和y一起往上跳,保持两者深度相同但不相汇。依然按照步骤一一样去枚举jump。只要F[x,jump]不等于F[y,jump],就赋值起跳。

    4.经过了步骤3的磨砺,x和y一定就差最后一步就可以相汇了。那么两者任意一个节点的父节点就必然是LCA(x,y)。所以此时LCA(x,y)=F[x,0]

    int lca(int x,int y){
        if(d[x]>d[y]) swap(x,y);
        for(int i=t;i>=0;i--){
            if(d[f[y][i]]>=d[x]) y=f[y][i];
            if(x==y) return x;    
        }
        for(int i=t;i>=0;i--){
            if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        }
        return f[x][0];
    }

     用途

    求树从x到y结点最短路径上所有节点的值之和

    其实这是写这篇博文的目的…

    怎么办呢?其实也只是个性质。即从根节点出发做一次单源最短路(或者直接Dfs)。那么Distance ( x , y ) = Distence ( x ) + Distence ( y ) - 2 * Distence ( Lca )

    所以只需要O(n)求最短路径,再求个LCA即可。

  • 相关阅读:
    mssql分页原理及效率分析
    [ActiveX]使用VS2010创建MFC ActiveX工程项目
    Study notes for Discrete Probability Distribution
    oracle存储过程异常捕获
    (Python学习9)Python虚拟机中的一般表达式
    用Arduino做一个可视化网络威胁级别指示器!
    iOS上线项目源码分享
    android实习程序6——拨号通话
    评价等级使用的五星选择,包含半星的选择
    AJAX实现无刷新验证用户名
  • 原文地址:https://www.cnblogs.com/Uninstalllingyi/p/11822227.html
Copyright © 2011-2022 走看看