LCA 的两种算法
来源:互联网 发布:bi数据分析前景 编辑:程序博客网 时间:2024/05/23 00:07
最近公共祖先的两种算法
Tarjan算法
Tarjan是LCA的一种离线算法,所谓离线指在执行算法前输入数据已知。
Tarjan的LCA算法基于深度优先搜索和并查集,而且并查集的合并操作明确要求了合并的的方向。
- 深度优先搜索会首先对当前节点的所有子树进行操作后回溯,假设子节点回溯之后其其对应的查询操作已经处理结束。我们就将它合并到当前节点的下方
- 合并完当前节点的所有子树之后,处理与当前节点有关的特定询问操作。即询问中含有当前节点,且另一个节点也已经深搜到
- 那么这一次询问的结果便是另一个节点所在集合的代表元素
倍增算法
倍增同样也基于深度优先搜索。
首先我们需要预处理出每个节点 u 的深度,和其 2 ^ i 的祖先 p[u][i]
预处理方法如下(使用链式前向星存图)
void dfs(int x) { p[x][0] = fa[x]; // 其 2 ^ 0 个祖先是其父节点 for (int i = 1; p[x][i-1]; i++) p[x][i] = p[p[x][i - 1]][i - 1]; // x 个节点的第 2 ^ i 个祖先既是 x 的第 2 ^ (i - 1) 个祖先的第 2 ^ (i - 1) 个祖先,可以动手推推这个式子。这也解释了 for 循环中使用 p[x][i-1] 作为判断表达式的原因 int to; for (int i = head[x]; i; i = edges[i].next) { // 枚举 x 节点能够到达的所有节点 to = edges[i].to; if (to != fa[x]) { //判断是否是当前节点的父节点 fa[to] = x; // 设置 x 的子节点的父节点为 x deep[to] = deep[x] + 1; // 设置子节点的深度为 x 的深度 +1 dfs(to); // 深搜子节点 } }}
需要通过调整使两个节点的深度位于同一层,然后将这两个节点同时向上查找指定距离的祖先
int lca(int a,int b){ if(deep[a] > deep[b]) swap(a, b); // 始终满足 b 为深度最大的节点 int f = deep[b] - deep[a]; // 计算两个节点的高度差 for (int i = 0; (1 << i) <= f; i++) if((1 << i) & f) b = p[b][i]; // 将 b 追溯到与 a 位于同一深度的祖先 if (a != b) { for (int i = 20; i >= 0; i--) // 从最深的祖先开始判断两个节点的祖先是否相同 if (p[a][i] != p[b][i]) { a = p[a][i]; b = p[b][i]; } a = p[a][0]; // 此时 a 和 b 的父节点既是其公共祖先 } return a;}
阅读全文
0 0
- LCA 的两种算法
- POJ1986-LCA问题的在线离线两种算法
- LCA问题的两种解法
- POJ-1330 LCA的两种写法
- LCA两种方法
- 浅谈LCA的几种算法
- LCA --- 常规的三种算法
- LCA的Tarjan算法
- LCA的离线算法
- LCA的倍增算法
- LCA的Tarjan离线算法
- LCA的tarjan算法理解
- 浅谈LCA的在线算法
- 浅谈LCA的离线算法
- LCA的离线算法 tarjan
- 浅谈LCA的离线算法
- LCA问题的Tarjan算法
- LCA的tarjan算法--总结
- 无限轮播
- 针对二分类问题的支持向量机模型
- 20170914
- Lintcode矩形面积
- C++/C++11中<iterator>的使用
- LCA 的两种算法
- HTTP 304状态码的详细讲解
- jdbc:oracle:thin:@lcoalhost:1521:orcl11解析
- 纸张尺寸
- 用 c# 来操作WORD的经验总结
- linux sed命令使用
- C语言写的循环单链表 例子简单 便于阅读和复习
- Java之split的坑
- freemarker常见语法