LCA ,也就是最近公共祖先是什么意思呢。

下面这张图可能会让你清楚的明白什么是最近公共祖先。

对于初始点,前提是它能构成一棵不成环的树,之所以不能成环,从定义就看出来了嘛,如果成环,是不是有种1是3的父亲,3是6的父亲,6又是1的父亲的感觉。O(∩_∩)O哈哈~

那么我们又从上面一句话能看出另一个问题了,那就是1是6的最远的祖先,3是6最近的祖先是不?

那么这就引出了最近公共祖先的概念了。

那么由上图举几个例子。

13 和11 的最近公共祖先就是6

13和2 的最近公共祖先就是1

8和6的最近公共祖先就是1

5和2的最近公共祖先是2

概念有了,那我们在编程的时候到底怎么去使用呢。

由于笔者也是刚入门,所以只会一种比较普遍的

Tarjin (离线算法)

这是一种比较常见的算法,用到了邻接表这个东西。

学长给我们当时讲是用vector容器作为邻接表。个人感觉很方便。所以在这顺便介绍一下。会的可以直接跳过。

************************************************************************

所谓邻接表,百度百科给出的定义不免显得很抽象,对于有向图,vi的邻接表中每个表结点都对应于以vi为始点射出的一条边。因此,将有向图的邻接表称为出边表。

在上面的那张表我们可以清晰的看出1的邻接点为2、3、4;

6的邻接点为3、10、11。

那么我们怎么来储存这种关系呢。

在这里我们用的是vector 容器来储存。

方式为:vector < int >  vec[n]   ;    //n为节点数,vec[i]就储存了i的邻接点。

如果需要储存两个参数,比如在查询的时候要按顺序输出,那么我们就可以弄个有两个参数的。

方式为:vector< pair <int ,int > >   query[n] ;

那么怎么存入元素呢,很显然是 query[x].push_back({y,i}) ;//y是邻接点,i是输入的序号,x是节点

那么怎么用呢,方法为:query[x][ j ].first ;//  j是第几个邻接点,这个表示的是y;同理表示i就是 :query[x][ j].second;

用法就到这里结束了。(ps:可能是我太菜了。。。)

*********************************************************************************************************************

那么邻接表有了,接下来怎么做呢,

在这里我们假设题目要你查询3、4节点的最近公共祖先和1、4节点的最近公共祖先!

在这里我们需要用到DFS来进行查找,直到找到根节点。

从上图我们可以发现用dfs查到了3节点。

我们用Q来表示查询是否有它需要查询的节点已经被查找了。

如果有那就直接将那个节点的父节点存起来(这里用的是并查集)。

为什么存父亲节点呢,其实到后面你就发现父亲节点就是最近共祖先!!!

黄色的数字表示该节点的父节点。

我们清晰的看到1、2、3节点原来的父亲节点是指向自己节点本身的,

3节点查询之后发现需要查询的节点(也就是4节点)没有被查找过的,

那么3节点的父亲节点指向2,并且返回2节点

然后2节点继续向邻接点查询,向4节点查询。

4节点父亲节点是4本身,然后查询,是否有需要查询的节点被访问过了,我们发现3节点被访问过了,那么我们将3节点的父亲节点存入结果中。并发现1节点也已经被访问过了,而且父亲节点还是1节点本身,那么我们也把结果存起来。

查询完了之后,将4节点的父亲节点指向2;并且返回2节点;

我们发现没有邻接点可以查了,

然后对2节点查询,发现没有要查询的,于是将2节点的父亲节点指向1,并且返回1节点;

然后对1节点进行查询,发现4节点已经访问过了。

于是我们将4节点的父亲节点覆盖掉我们之前存的答案,

但是我们很明显的发现,通过并查集4的父亲节点这时候已经指向1了,所以覆盖并不影响结果。

最后我们就跳出了dfs,并且我们已经完成了所有的查询。

于是在主函数输出结果就ok,答案应该是

2

1

这就是最近公共祖先的基本求解思路,用到了邻接表,dfs,并查集。

这种方法也是最常用的算法来求最近公共祖先了,具有一定的普适性。

ps:可能是我不会其他方法吧,O(∩_∩)O哈哈~

还有就是上面几张图明显看出纯手画,画的不好,多多包涵哈。

这就是

Tarjin (离线算法)的基本思路了。

如果有不对的地方,望dalao 们在评论区指正,O(∩_∩)O谢谢~

现在放出一道模板题。附上AC代码;

POJ-1330

Nearest Common Ancestors

AC 代码如下:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<vector>
 4 #include<string.h>
 5 #include<algorithm>
 6 #define N  100005
 7 using namespace std;
 8 int vis[N],pre[N],ans[N];
 9 vector <int> vec[N];
10 vector <pair <int,int> > query[N];
11 int Find(int x)
12 {
13     if(pre[x]==x)
14     {
15         return x;
16     }
17     else
18     {
19         pre[x]=Find(pre[x]);
20         return pre[x];
21     }
22 }
23 void dfs(int u,int fa)
24 {
25     pre[u]=u;
26     vis[u]=1;
27     for(int i=0;i<vec[u].size();i++)
28     {
29         int v=vec[u][i];
30         if(v==fa) continue;//防止走回头路
31         dfs(v,u);//邻接表查询
32     }
33     for(int i=0;i<query[u].size();i++)//查询
34     {
35         int v=query[u][i].first;
36         int id=query[u][i].second;
37         if(vis[v]==1)
38         {
39             ans[id]=Find(v);
40         }
41     }
42     pre[u]=fa;//查询完毕,指向父亲节点。
43
44 }
45 int main()
46 {
47     int T;
48     cin>>T;
49     while(T--)
50     {
51         memset(vis,0,sizeof(vis));
52         memset(ans,0,sizeof(ans));
53         memset(pre,0,sizeof(pre));
54         int n,x,y;
55         cin>>n;
56         for(int i=0;i<n-1;i++)
57         {
58             cin>>x>>y;
59             vec[x].push_back(y);
60             vec[y].push_back(x);
61             vis[y]=1;
62         }
63         int q;
64         q=1;
65         for(int i=0;i<q;i++)
66         {
67             cin>>x>>y;
68             query[x].push_back({y,i});
69             query[y].push_back({x,i});
70         }
71         for(int i=1;i<=n;i++)
72         {
73             if(vis[i]==0)
74             {
75                 memset(vis,0,sizeof(vis));
76                 dfs(i,i);
77                 break;
78             }
79         }
80         for(int i=0;i<q;i++)
81         {
82             cout<<ans[i]<<endl;
83         }
84         for(int i=1;i<=n;i++)
85         {
86             vec[i].clear();
87             query[i].clear();
88         }
89     }
90     return 0;
91 }

转载于:https://www.cnblogs.com/ISGuXing/p/7219889.html

LCA 最近公共祖先相关推荐

  1. LCA(最近公共祖先)问题

    1.这个算法基于并查集和深度优先搜索.算法从根开始,对每一棵子树进行深度优先搜索,访问根时,将创建由根结点构建的集合,然后对以他的孩子结点为根的子树进行搜索,使对于 u, v 属于其某一棵子树的 LC ...

  2. Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)...

    转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2194090a96bbed2db1351de8.html 基本概念: 1.割点:若删掉某点后,原连通图 ...

  3. LCA 最近公共祖先(RMQ、树上倍增、Tarjan),树上两点距离,线段重合长度

    对于LCA的一些理解 RMQ dfs处理树 对于一个树形结构,可以用dfs将一颗树转化成数组,数组中记录每个点的标号,这样数组就按照dfs的顺序把树存了下来 确定祖先的范围 对于询问的节点X和Y, X ...

  4. POJ 1330 LCA最近公共祖先 离线tarjan算法

    题意要求一棵树上,两个点的最近公共祖先 即LCA 现学了一下LCA-Tarjan算法,还挺好理解的,这是个离线的算法,先把询问存贮起来,在一遍dfs过程中,找到了对应的询问点,即可输出 原理用了并查集 ...

  5. LCA(最近公共祖先)(leetcode 236 python C++)

    LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. # Definition for a binary tree node. ...

  6. 故事篇之 LCA 最近公共祖先(一)

    故事出真知 阿珍 爱上了 阿强 但 被他们的父母 拒绝 了 没错 狗血的近亲结婚剧情开始了 阿珍 说: 不行,我深深爱着我的阿强,谁也不能把我们分开 阿强 深情地望着阿珍 说 一定会有机会的! 此时 ...

  7. 模板 - LCA最近公共祖先(倍增法、Tarjan、树上差分、LCA优化的次小生成树)

    整理的算法模板合集: ACM模板 注意x和y的LCA可以是x或者y本身 一.LCA的在线倍增算法 /*给定一棵包含 n个节点的有根无向树,有 m个询问,每个询问 给出了一对节点的编号 x和 y,询问 ...

  8. LCA 最近公共祖先 详解

    一.内容 给定一棵包含 n 个节点的有根无向树,节点编号互不相同,但不一定是 1∼n.有 m 个询问,每个询问给出了一对节点的编号 x 和 y,询问 x 与 y 的祖孙关系.输入格式 输入第一行包括一 ...

  9. LeetCode Lowest Common Ancestor of a Binary Search Tree (LCA最近公共祖先)

    题意: 给一棵二叉排序树,找p和q的LCA. 思路: 给的是BST(无相同节点),那么每个节点肯定大于左子树中的最大,小于右子树种的最小.根据这个特性,找LCA就简单多了. 分三种情况: (1)p和q ...

最新文章

  1. 在 Linux 上给用户赋予指定目录的读写权限
  2. 你绝对能懂的“机器学习”(四)
  3. android studio自动注释
  4. 学车比学计算机简单,帅哥自述:学车比上班还要累
  5. 1.3. kermit
  6. CCP(Cost complexity pruning) on sklearn with python implemention
  7. Mysql数据库使用总结
  8. python的urllib四大模块_Python常用的内建模块4:urllib
  9. 有关PHP、HTML单引号、双引号转义以及转成HTML实体的那些事!
  10. JSON(5)---JSON.stringify()
  11. SVN汉化失败的原因及解决方案(通过SVN官网下载SVN和相应的汉化包)
  12. python数字信号处理pdf_数字信号处理
  13. 消消乐游戏原理(附部分代码)
  14. 超详细的Latex快速基础入门(第一节)
  15. HDU 2201 熊猫阿波问题==金刚坐飞机问题
  16. Linux之常见面试题知识点批注(七)
  17. 蹩脚的Access分页语句
  18. html+css主页页眉实现
  19. php html 纯文本,php – 使用纯文本回退发送HTML简报
  20. LVTTL与LVCMOS区别

热门文章

  1. 浅谈游戏程序设计入门
  2. 数据结构中符号的作用(图解)
  3. 第三方网站用户和微信用户的绑定方法
  4. wordpress禁用Gutenberg(古藤保)编辑器代码
  5. 股票配资平台安全可靠吗?一文告诉你!
  6. python声明一个数组_python 声明数组
  7. 阿斯利康英飞凡在华获批用于治疗广泛期小细胞肺癌;​君实生物与嘉晨西海成立合资公司 | 医药健闻...
  8. 30个农村创业项目_6个适合百姓的冷门创业项目,乡村乡镇,小本生意却受农村人欢迎...
  9. [2019编程]第六节教学大纲:学生类Student的基本概念及初步应用/CSS选择器的种类
  10. Windows 7 升级顾问