• 最近公共祖先LCA详细解法


    最近公共祖先(LCA)是树上倍增的一种典型例题。

    问题描述:给定一棵具有n个节点的树,询问两个节点x,y的最近的公共祖先。

    分析:首先我们想到的是暴力算法,当然这个算法妥妥的会TLE掉,所以我们采用倍增优化的方法来进行实现,也就是我们今天介绍的重点。

      所谓倍增,就是按2的倍数来增大,按1,2,4,8,16......来跳。不过我们不能按正着的顺序跳,需要按......16,8,4,2,1的顺序来跳。因为如果从小的开始跳,有可能出现“悔棋”的现象(5 不等于 1 + 2 +4,这样就必须要往回跳两个)。

      要想实现这个算法,我们就必须要记录各个点的深度和他们2的i次方的祖先,用一个二维数组可以完美解决~

      代码如下:

    void dfs(int f,int fath) //f表示当前节点,fath表示它的父亲节点
    {
        depth[f]=depth[fath]+1;
        fa[f][0]=fath;
        for(int i=1;(1<<i)<=depth[f];i++)
            fa[f][i]=fa[fa[f][i-1]][i-1]; //这个转移可以说是算法的核心之一
                                    //意思是f的2^i祖先等于f的2^(i-1)祖先的2^(i-1)祖先
                                    //2^i=2^(i-1)+2^(i-1)
        for(int i=head[f];i;i=e[i].nex)
            if(e[i].t!=fath)
               dfs(e[i].t,f);
    }
    

      接下来我们就可以取LCA了

    int lca(int x,int y)
    {
    if(depth[x]<depth[y]) //用数学语言来说就是:不妨设x的深度 >= y的深度
      swap(x,y);
    while(depth[x]>depth[y])
      x=fa[x][lg[depth[x]-depth[y]]-1]; //先跳到同一深度
    if(x==y)  //如果x是y的祖先,那他们的LCA肯定就是x了
      return x;
    for(int k=lg[depth[x]]-1;k>=0;k--) //不断向上跳(lg就是之前说的常数优化)
      if(fa[x][k]!=fa[y][k])  //因为我们要跳到它们LCA的下面一层,所以它们肯定不相等,如果不相等就跳过去。
        x=fa[x][k], y=fa[y][k];
    return fa[x][0];  //返回父节点
    }
    

      总体来说就是这样了,不知道各位大佬有没有看懂呢?

  • 相关阅读:
    matlab中figure 创建图窗窗口
    matlab中imread 从图形文件读取图像
    matlab中imfinfo 有关图形文件的信息
    matlab中bitshift 将位移动指定位数
    matlab中reshape 重构数组
    matlab中find 查找非零元素的索引和值
    比特数
    matlab中fseek 移至文件中的指定位置
    poj 1039 Pipe(几何基础)
    poj 1556 The Doors(线段相交,最短路)
  • 原文地址:https://www.cnblogs.com/byfrc/p/9892870.html
Copyright © 2020-2023  润新知