最近公共祖先 tarjan离线算法 C++

最近做到一道题目,大概的意思就是求一个多叉树中两个节点的最近公共祖先,输入是用邻接矩阵表示的。

要想理解tarjan算法并实现它,需要先理解一下内容:

1) 深度优先搜索;tarjan算法核心思想:当某节点刚刚搜索完毕时,看与其相关的结点v是否已经被访问,如果v已经被访问过了,则它们的最近公共祖先就是v的祖先。

2) 并查集原理和实现方法,并查集的代表和祖先的区别(其实也可以一起表示),祖先的更新时刻

3) 如何表示多叉数(邻接链表,邻接矩阵),如何表示查询对,如何记录查询结果

下面是c++实现代码,比较偷懒,每次调用函数就查询一个。查询对的数据结构可以用下面提到的邻接表来表示。

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>

using namespace std;

class lca{
public:
    lca(const vector<string> &vstr)
        :str(vstr),f(vstr.size(),-1),ancestor(vstr.size(),-1),visit(vstr.size(),0) { }
    int lca_query(int vertex,int u, int v){
        static int ans=-1;
        ancestor[vertex] = vertex;
        visit[vertex] = true;
        for (int i = 0; i < str.size(); ++i){
            if ((str[vertex][i] == ‘1‘) && (visit[i] == 0)){
                ans=lca_query(i, u, v);
                unite(vertex, i);
                ancestor[find(vertex)] = vertex;
            }
        }
        if (vertex == u&&visit[v])
            ans = ancestor[find(v)];
        if (vertex == v&&visit[u])
            ans = ancestor[find(u)];
        return ans;
    }
private:
    const vector<string> &str;
    vector<int> f;  //并查集
    vector<int> ancestor;
    vector<bool> visit;
    int find(int i)
    {
        if (f[i] == -1)
            return i;
        return f[i] = find(f[i]);
    }

    void unite( int u, int v)
    {
        int x = find(u);
        int y = find(v);
        if (x != y)
            f[x] = y;
    }

};

int main(){
    vector<string> v123 = { "01100001", "10011000", "10000000", "01000000", "01000110","00001000","00000100","10000000" };
    lca query1(v123);
    cout << query1.lca_query(0,4, 7);

}

实际上用邻接矩阵来表示多叉数是很浪费时间的,单颗多叉树作为无环图,只有(n-1)条边,这里n是节点数。网上有很好的方法来表示邻接链表,

struct Edge
{
    int to, next;
}edge[maxn * 2];
int head[maxn], tot;
void addedge(int u, int v)//邻接表头插法加边
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}

本质上就是一个单链表,不过这个单链表的next指针只是一个数组下标值。head[u]记录的是上一次从u出发的边的数组下边。

要理解tarjan算法,得先理解并查集

时间: 2024-10-17 02:50:46

最近公共祖先 tarjan离线算法 C++的相关文章

笔记:LCA最近公共祖先 Tarjan(离线)算法

LCA最近公共祖先 Tarjan他贱(离线)算法的基本思路及其算法实现 本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig/article/details/52336496 https://baike.baidu.com/item/最近公共祖先/8918834?fr=aladdin 最近公共祖先简称LCA(Lowest Common Ancesto

LCA最近公共祖先 Tarjan离线算法

学习博客:  http://noalgo.info/476.html 讲的很清楚! 对于一颗树,dfs遍历时,先向下遍历,并且用并查集维护当前节点和父节点的集合.这样如果关于当前节点(A)的关联节点(B)(及要求的最近祖先的另一个点)之前被访问过,那么 B可定已经属于一个集合,先前对于访问过的点,已经维护了那个点所在集合的根,所以找到B节点所在集合的根,那么这个点就是最近的根,因为对于dfs访问的顺序.

POJ 1330 Nearest Common Ancestors(最近公共祖先 Tarjan离线)

题目链接:http://poj.org/problem?id=1330 题目: Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the ro

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11320    Accepted Submission(s): 4119 Problem Description There are n houses in the village and some bidirectional roads c

LCA(最近公共祖先)——离线 Tarjan 算法

一.梳理概念 定义:对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 通俗地讲,最近公共祖先节点,就是两个节点在这棵树上深度最大的公共的祖先节点,即两个点在这棵树上距离最近的公共祖先节点. 提示:父亲节点也是祖先节点,节点本身也是它的祖先节点. 给出一棵树,如图所示: 由上面的定义可知:3和5的最近公共祖先为1,5和6的最近公共祖先为2,2和7的最近公共祖先为2, 6和7的最近公共祖先为4. 二.繁文缛节 注意注意注意!!!尚

HDU 2586 How Far Away?(Tarjan离线算法求lca)

题意:给定一棵树n个节点m个询问,每次询问两个节点之间的距离. 思路:Tarjan离线算法求lca. 这题一开始交了n发一直爆栈.......百度了一下大概说的是这样hdu用的是windows服务器所以栈大小极其坑爹,稍微深一点的递归就会爆栈(正式比赛一般不会爆) 解决方法就是加一句#pragma comment(linker, "/STACK:1024000000,1024000000") 用c++交就好.....当然这只是针对比较坑爹oj来说的取巧的方法 #include<c

[图论] LCA(最近公共祖先)Tarjan 离线算法

很好的参考资料:http://taop.marchtea.com/04.04.html    下面的配图和部分文字转载于此文章 离线算法就是指统一输入后再统一输出,而不是边输入边实时输出.Tarjan算法的复杂度为O(N+Q),Q为询问的次数. 由于是离线算法,所以要保存输入的信息,次序问题. 若两个结点u.v分别分布于某节点t 的左右子树,那么此节点 t即为u和v的最近公共祖先.更进一步,考虑到一个节点自己就是LCA的情况,得知: ?若某结点t 是两结点u.v的祖先之一,且这两结点并不分布于该

【C++】最近公共祖先LCA(Tarjan离线算法)&amp;&amp; 洛谷P3379LCA模板

1.前言 首先我们介绍的算法是LCA问题中的离线算法-Tarjan算法,该算法采用DFS+并查集,再看此算法之前首先你得知道并查集(尽管我相信你如果知道这个的话肯定是知道并查集的),Tarjan算法的优点在于相对稳定,时间复杂度也比较居中,也很容易理解(个人认为). 2.思想 下面详细介绍一下Tarjan算法的思想: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5.寻找与当前点

POJ 1330 Nearest Common Ancestors 【最近公共祖先LCA算法+Tarjan离线算法】

Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20715   Accepted: 10910 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each