Tarjan打包总结(求强连通分量、割点和Tarjan-LCA)

写给自己的Tarjan算法总结,包括求强连通分量、割点和Tarjan-LCA,基础概念就没有废话了,只写自己的理解和板子

强连通分量&缩点

原理

在DFS生成树中,如果一个节点通过其所有子节点的返祖边恰能达到这个节点,那么这些满足条件的点中最高的那个节点一定是强连通分量

伪代码

tarjan(u)
{
DFN[u]=Low[u]=++Index // 为节点u设定次序编号和Low初值
Stack.push(u) // 将节点u压入栈中
for each (u, v) in E // 枚举每一条边
if (v is not visted) // 如果节点v未被访问过
tarjan(v) // 继续向下找
Low[u] = min(Low[u], Low[v])
else if (v in S) // 如果节点v还在栈内
Low[u] = min(Low[u], DFN[v])
if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根
repeat
v = S.pop // 将v退栈,为该强连通分量中一个顶点
print v
until (u== v)
}

板子(C++)

void tarjan(int u){
dfn[u]=++cnt;
low[u]=cnt;
ins[u]=1;
s[++top]=u;
for(register int i=head[u];i;i=nxt[i]){
int v=vv[i];
if(dfn[v]==0){
tarjan(v);
low[u]=MIN(low[u],low[v]);
}else if(ins[v])
low[u]=MIN(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
ins[u]=0;
while(s[top]!=u){
//do something
ins[s[top]]=0;
top--;
}
top--;
}
}

割点

原理

思路同上,如果一个节点不为根节点且只要有一个子节点通过返祖边不能到达这个节点的祖先节点,那么这个节点就一定是一个割点。而如果这个节点是个根节点的话,只要其子树数大于1就一定是个割点了。

例如下图中,1和2就是割点

dfs生成树:

实边为树边,虚线为返祖边

伪代码

tarjan(u, fa){
dfn[u]=low[u]=++index // 为节点u设定次序编号和Low初值
int cnt=0; //统计子节点个数
for each (u, v) in E // 枚举每一条边
cnt++;
if (v is not visted) // 如果节点v未被访问过
tarjan(v);
low[u]=min(low[u], low[v]);
if(u is root and cnt>1) //如果当前节点是根节点且其子树数大于1
ans[u]=1; //那么节点u就是一个割点
else if(low[v]>=dfn[u]) //如果有一个子节点v通过返祖边不能到达这个节点的祖先节点
ans[u]=1; //那么节点u就是一个割点
else if(v!=fa) //必须确保节点不为其父亲,否则会陷入死循环
low[u]=min(low[u], low[v]);
}

最近公共祖先(LCA)

原理

因为DFS遍历的性质,所以任意一对询问第一次都已经被访问到时,此时在已经访问过的最低且度不为0的节点就是这次询问的公共祖先(其实另外一个doubly在线算法也是利用了DFS遍历的性质,异曲同工之妙)

伪代码

tarjan-lca(u)//marge和find为并查集合并函数和查找函数
{
for each(u,v) //访问所有u子节点v
{
Tarjan(v); //继续往下遍历
marge(u,v); //合并v到u上
标记v被访问过;
}
for each(u,e) //访问所有和u有询问关系的e
{
如果e被访问过;
u,e的最近公共祖先为find(e);
}
}

板子

void tarjan-lca(int u, int fa){
fa[u]=u;//并查集初始化
for(register int i=0;i<e[u].size();i++){
int v=e[u][i];
if(v==fa) continue;
Tarjan(v);
fa[v]=u;//merge
}
for(register int i=0;i<q[u].size();i++){
int v=q[u][i].data;
if(fa[v]) ans[q[u][i].id]=find(v);
}
}

本文采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可。欢迎转载,请注明出处: 转载自:Santiego的博客

Tarjan算法打包总结(求强连通分量、割点和Tarjan-LCA)的更多相关文章

  1. 求强连通分量模板(tarjan算法)

    关于如何求强连通分量的知识请戳 https://www.byvoid.com/blog/scc-tarjan/ void DFS(int x) { dfn[x]=lowlink[x]=++dfn_cl ...

  2. 模板 - 强连通分量/割点/桥 - Tarjan

    int dfn[N], low[N], dfncnt, s[N], tp; int scc[N], sc; // 结点 i 所在 scc 的编号 int sz[N]; // 强连通 i 的大小 voi ...

  3. Tarjan求强连通分量,缩点,割点

    Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...

  4. tarjan算法-解决有向图中求强连通分量的利器

    小引 看到这个名词-tarjan,大家首先想到的肯定是又是一个以外国人名字命名的算法.说实话真的是很佩服那些算法大牛们,佩服得简直是五体投地啊.今天就遇到一道与求解有向图中强连通分量的问题,我的思路就 ...

  5. Tarjan求强连通分量、求桥和割点模板

    Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...

  6. tarjan求强连通分量+缩点+割点以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  7. tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  8. Tarjan 算法求 LCA / Tarjan 算法求强连通分量

    [时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarj ...

  9. 【学习整理】Tarjan:强连通分量+割点+割边

    Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量.   算法可以在 ...

随机推荐

  1. ubuntu 下正确安装android手机驱动

    1. 查看手机ID号. charlesxue@THSHIBA:~/setup/cocos2d-x/cocos2d-x-/projects/simpleGame/proj.android/bin$ ls ...

  2. 258. Add Digits 数位相加到只剩一位数

    [抄题]: Given a non-negative integer num, repeatedly add all its digits until the result has only one ...

  3. SpringMVC Controller 的简单应用

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  4. 62-U型数字

    https://nanti.jisuanke.com/t/20683 #include <iostream> using namespace std; int main(){ int ct ...

  5. System.Web.UI.Page事件执行顺序

    #region OnPreInit 第一步(显式重写,文章下面有隐式重写) protected override void OnPreInit(EventArgs e) { //检查 IsPostBa ...

  6. GlobalAlloc()和malloc()、HeapAlloc()

    两者都是在堆上分配内存区.  malloc()是C运行库中的动态内存分配函数,WINDOWS程序基本不使用了,因为它比WINDOWS内存分配函数少了一些特性,如,整理内存.  GlobalAlloc( ...

  7. tornado+nginx上传视频文件

    [http://arloz.me/tornado/2014/06/27/uploadvideotornado.html] [NGINX REFRER:Nginx upload module] 由于to ...

  8. Android Hander、Looper、Message三者之间的联系

    1.首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象:因为Looper.prepare()在一个线程中只能调用一次,所以Mess ...

  9. 小议C#接口的隐式与显示实现(续)

    上文连接,讲的比较模糊,而且调用起来感觉比较混乱 http://www.cnblogs.com/walleyekneel/p/3581489.html 这次改为显式接口调用,可能项目也有这个一个需求 ...

  10. WPF 控件库——仿制Chrome的ColorPicker

    WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...