LCA(Lowest Common Ancesor)
LCA(Lowest Common Ancesor)
1.基于二分搜索算法
预处理father[v][k]表示v的2的k次方层祖先,时间复杂度是O(nlogn),每次查询的时间复杂度是O(logn),预处理2k表的技巧在LCA之外也会用到。用链式前向星存图,相对vector邻接表要快。
一次dfs预处理出全部点的父亲结点,然后用2分思想,处理出每个点的2的k次方的父亲结点,对于LCA核心算法,首先把深度较深的移动到与另外一个水平,然后两个结点一起移动,但他们的父亲结点不同时,先上移动,最后返回当前结点的父亲结点。
1.1 Nearest Common Ancestors POJ - 1330
在有根树下,求任意两个结点的LCA,首先找到根节点,以这个结点为起点dfs,预处理出所有结点的父节点。
链式前向星存
#include<iostream>
#include<cstring>
#include<cmath>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
const int N = 1e4 + 5;
int fa[N][15];
int head[N];
int vis[N];
int cur;
int depth[N];
bool Du[N];
int ans[N];
int n;
struct Edge {
int to;
int nex;
}edge[N];
void AddEdge(int u, int v) {
edge[cur].to = v;
edge[cur].nex = head[u];
head[u] = cur++;
}
void init() {
mem(head, -1);
mem(fa, 0);
mem(Du, 0);
mem(depth, 0);
cur = 0;
}
void dfs(int v, int p, int d) {
fa[v][0] = p;
depth[v] = d;
for (int i = head[v]; i != -1; i = edge[i].nex) {
dfs(edge[i].to, v, d + 1);
}
}
int LCA(int s, int t) {
if (depth[s] < depth[t])
swap(s, t);
int temp = depth[s] - depth[t];
for (int i = 0; (1 << i) <= temp; i++)
{
if ((1<<i)&temp)
s = fa[s][i];
}
if (s == t)return s;
for (int i = (int)log2(n*1.0); i >= 0; i--) {
if (fa[s][i] != fa[t][i]) {
s = fa[s][i];
t = fa[t][i];
}
}
return fa[s][0];
}
int main()
{
int T, s, t, root;
cin >> T;
while (T--)
{
init();
cin >> n;
for (int i = 0; i < n - 1; i++) {
cin >> s >> t;
AddEdge(s, t);
Du[t] = 1;
}
for (int i = 1; i <= n; i++){
if (Du[i] == 0){
root = i;
break;
}
}
dfs(root, -1, 0);
for (int j = 0; (1 << (j + 1)) < n; j++) {
for (int i = 1; i <= n; i++) {
if (fa[i][j] < 0)
fa[i][j + 1] = -1;
else fa[i][j + 1] = fa[fa[i][j]][j];
}
}
cin >> s >> t;
cout << LCA(s, t) << endl;
}
}
连接表存
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
const int N = 1e4 + 5;
int father[N][15];
int depth[N];
int Du[N];
int max_log;
struct Node{
vector<int>G;
};
Node tree[N];
void dfs(int v, int p, int d) {
father[v][0] = p;
depth[v] = d;
for (int i = 0; i < tree[v].G.size(); i++) {
if (tree[v].G[i] != p)dfs(tree[v].G[i], v, d + 1);
}
}
void init() {
memset(Du, 0, sizeof(Du));
//for (int i = 0; i < 15; i++)G[i].clear();
memset(tree, 0, sizeof(tree));
memset(depth, 0, sizeof(depth));
memset(father, 0, sizeof(father));
}
int LCA(int u, int v) {
if (depth[u]>depth[v])swap(u, v);
int temp = depth[v] - depth[u];
for (int i = 0; (1 << i) <= temp; i++) {
if ((1 << i)&temp) {//如果temp是1011,1分别左移1,2,3,4位,与temp&,如果当前temp在i为1,说明可以提高i位
v= father[v][i];//depth[v]大,先将v提高与u水平
}
}
if (u == v)return u;
for (int i = max_log; i >= 0; i--) {
if (father[u][i] != father[v][i]) {
u = father[u][i];
v = father[v][i];
}
}
return father[u][0];
}
int main() {
int T, s, t, root;
cin >> T;
while (T--)
{
int n;
cin >> n;
init();
max_log = int(log2(1.0*n));
for (int i = 0; i < n - 1; i++) {
cin >> s >> t;
tree[s].G.push_back(t);
Du[t] = 1;
}
for (int i = 1; i <= n; i++) {
if (Du[i] == 0) {
root = i;
break;
}
}
dfs(root, -1, 0);
for (int j = 0; (1 << (j + 1)) < n; j++) {
for (int i = 1; i <= n; i++) {
if (father[i][j] < 0)
father[i][j + 1] = -1;
else father[i][j + 1] = father[father[i][j]][j];
}
}
cin >> s >> t;
cout << LCA(s, t) << endl;
}
return 0;
}
树上最短距离Factory HDU - 6115
暴力LCA
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define mem(a,x) memset(a,x,sizeof(a))
const int INF = 0x3f3f3f3f;
using namespace std;
const int N = 100010;
int fa[N][25];
int head[N];
int cur;
int depth[N];
int dis[N];//到根节点的距离
vector<int>vec[N];
int n,m;
struct Edge {
int to;
int cost;
int nex;
}edge[2*N];
//edge[i].to表示第i条边的终点,edge[i].nex表示与第i条边同起点的下一条边的存储位置,edge[i].cost为边权值.
//head[i]保存的是以i为起点的所有边中编号最大的那个, 而把这个当作顶点i的第一条起始边的位置
void AddEdge(int u, int v, int w) {
edge[cur].to = v;
edge[cur].cost = w;
edge[cur].nex = head[u];
head[u] = cur++;
}
void init() {
mem(head, -1);
mem(fa, 0);
mem(depth, 0);
mem(dis, 0);
cur = 0;
}
void dfs(int v, int p, int d,int cost) {
fa[v][0] = p;
depth[v] = d;
dis[v] = cost;
for (int i = head[v]; i != -1; i = edge[i].nex) {
if(!depth[edge[i].to])//无向图
dfs(edge[i].to, v, d + 1,dis[v]+edge[i].cost);
}
}
/*
void dfs(int v, int f, int cost)
{
dis[v] = cost;
for (int i = head[v]; i != -1; i = edge[i].nex)
{
int u = edge[i].to;
if (u == f) continue;
if (!depth[u])
depth[u] = depth[v] + 1, fa[u][0] = v, dfs(u, v, dis[v] + edge[i].cost);
}
}
*/
int LCA(int s, int t) {
if (depth[s] < depth[t])
swap(s, t);
int temp = depth[s] - depth[t];
for (int i = 0; (1 << i) <= temp; i++)
{
if ((1 << i)&temp)
s = fa[s][i];
}
if (s == t)return s;
for (int i = (int)log2(n*1.0); i >= 0; i--) {
if (fa[s][i] != fa[t][i]) {
s = fa[s][i];
t = fa[t][i];
}
}
return fa[s][0];
}
int main()
{
int T, s, t,w, root;
scanf("%d", &T);
while (T--)
{
init();
scanf("%d%d", &n, &m);
for (int i = 0; i < n - 1; i++) {
scanf("%d%d%d", &s, &t, &w);
AddEdge(s, t,w);
AddEdge(t, s, w);
//Du[t] = 1;
}
//找到根节点
for (int i = 1; i <= m; i++)
{
int num, v;
scanf("%d", &num);
for (int j = 1; j <= num; j++)
{
scanf("%d", &v);
vec[i].push_back(v);
}
}
//选择1为根
dfs(1, -1,0,0);
for (int j = 0; (1 << (j + 1)) < n; j++) {
for (int i = 1; i <= n; i++) {
if (fa[i][j] < 0)
fa[i][j + 1] = -1;
else fa[i][j + 1] = fa[fa[i][j]][j];
}
}
int q;
scanf("%d",&q);
for (int i = 1; i <= q; i++)
{
int v, u, ans = INF;
scanf("%d%d", &v, &u);
for (int j = 0; j < vec[v].size(); j++)
for (int k = 0; k < vec[u].size(); k++)
ans = min(ans, dis[vec[v][j]] + dis[vec[u][k]] - dis[LCA(vec[v][j], vec[u][k])] * 2);
printf("%d\n", ans);
}
for (int i = 1; i <= m; i++) vec[i].clear();
}
return 0;
}
LCA(Lowest Common Ancesor)的更多相关文章
- Leetcode之深度优先搜索(DFS)专题-1123. 最深叶节点的最近公共祖先(Lowest Common Ancestor of Deepest Leaves)
Leetcode之深度优先搜索(DFS)专题-1123. 最深叶节点的最近公共祖先(Lowest Common Ancestor of Deepest Leaves) 深度优先搜索的解题详细介绍,点击 ...
- LeetCode 236. 二叉树的最近公共祖先(Lowest Common Ancestor of a Binary Tree)
题目描述 给定一棵二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义: “对于有根树T的两个结点u.v,最近公共祖先表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. ...
- LCA(最近公共祖先)算法
参考博客:https://blog.csdn.net/my_sunshine26/article/details/72717112 首先看一下定义,来自于百度百科 LCA(Lowest Common ...
- Tarjan算法离线 求 LCA(最近公共祖先)
本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig ...
- LCA(最近公共祖先)--tarjan离线算法 hdu 2586
HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
- leetcode 236. 二叉树的最近公共祖先LCA(后序遍历,回溯)
LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百 ...
- PAT A1143 Lowest Common Ancestor (30 分)——二叉搜索树,lca
The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U ...
- LeetCode 235. Lowest Common Ancestor of a Binary Search Tree (二叉搜索树最近的共同祖先)
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BS ...
- Lowest Common Ancestor of a Binary Search Tree(Java 递归与非递归)
题目描述: Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in ...
随机推荐
- C#模拟客户端发送数据示例
在给一些客户端做服务器端支持时,发现他们提交上来的数据大都不是http请求格式,因而使用Request.Form获取不到内容,今天用C#做下模拟,并演示下数据接收. 1.发送文本 1).客户端发送 ...
- 面试汇总——说一下CSS盒模型
本文是面试汇总分支——说一下CSS盒模型. 基本概念:W3C标准盒模型和IE盒模型 CSS如何设置这两种模型 JS如何获取盒模型对应的宽和高 根据盒模型解释边距重叠 BFC(边距重叠解决方案) 一. ...
- 3分钟搞明白信用评分卡模型&模型验证
信用评分卡模型在国外是一种成熟的预测方法,尤其在信用风险评估以及金融风险控制领域更是得到了比较广泛的使用,其原理是将模型变量WOE编码方式离散化之后运用logistic回归模型进行的一种二分类变量的广 ...
- 解决CEF中显示Flash动画弹出安全警告问题
一. 1.Xilium.CefGlue. CefApp (CefApp.cs文件)类on_before_command_line_processing方法内设置flash路径.版本号等. m_comm ...
- Android 隐藏系统状态栏
通常的做法是这样的: private static boolean isStatusbarVisible(Activity activity) { int uiOptions = activity.g ...
- Atitit 热烈庆祝读经器项目圆满完成
Atitit 热烈庆祝读经器项目圆满完成 1.1. 读经器项目简单介绍 1 1.2. 一万小时定律和十年一个专家定律 1 1.3. 获得加持前景 1 1.4. 核心源码 1 1.5. 项目git 2 ...
- Linux基础知识之用户和用户组以及 Linux 权限管理
已经开始接触Linux用户管理,用户组管理,以及权限管理这几个逼格满满的关键字.这几个关键字对于前端程序猿的我来说真的是很高大上有木有,以前尝试学 Linux 的时候看到这些名词总是下意识的跳过不敢看 ...
- [20180312]进程管理其中的SQL Server进程占用内存远远大于SQL server内部统计出来的内存
sql server 统计出来的内存,不管是这个,还是dbcc memorystatus,和进程管理器中内存差距很大,差不多有70G的差异. 具体原因不止,可能是内存泄漏,目前只能通过重启服务解决 ...
- php cli模式下获取参数的方法
转载声明:http://blog.csdn.net/fdipzone/article/details/51945892 php在cli模式下接收参数有两种方法 1.使用argv数组 <?php ...
- C# 耗时统计
Stopwatch sw = new Stopwatch(); sw.Restart(); var a = redis.ListRange<UserModel>(key); sw.Stop ...