Tarjan算法打包总结(求强连通分量、割点和Tarjan-LCA)
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)的更多相关文章
- 求强连通分量模板(tarjan算法)
关于如何求强连通分量的知识请戳 https://www.byvoid.com/blog/scc-tarjan/ void DFS(int x) { dfn[x]=lowlink[x]=++dfn_cl ...
- 模板 - 强连通分量/割点/桥 - Tarjan
int dfn[N], low[N], dfncnt, s[N], tp; int scc[N], sc; // 结点 i 所在 scc 的编号 int sz[N]; // 强连通 i 的大小 voi ...
- Tarjan求强连通分量,缩点,割点
Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...
- tarjan算法-解决有向图中求强连通分量的利器
小引 看到这个名词-tarjan,大家首先想到的肯定是又是一个以外国人名字命名的算法.说实话真的是很佩服那些算法大牛们,佩服得简直是五体投地啊.今天就遇到一道与求解有向图中强连通分量的问题,我的思路就 ...
- Tarjan求强连通分量、求桥和割点模板
Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...
- tarjan求强连通分量+缩点+割点以及一些证明
“tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄> 自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...
- tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明
“tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄> 自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...
- Tarjan 算法求 LCA / Tarjan 算法求强连通分量
[时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarj ...
- 【学习整理】Tarjan:强连通分量+割点+割边
Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量. 算法可以在 ...
随机推荐
- realsense and Mask_RCNN
###################librealsense and Mask_RCNN cd RealSennse/librealsense2018091501/librealsense/wrap ...
- Docker学习笔记_下载镜像更换为国内源,实现快速下载image
1.编辑/etc/docker/daemon.json,增加下面内容: { "registry-mirrors": ["https://registry.docker-c ...
- c语言实践:求两个数的最大公约数
我的思路是这样的:比如12和16这两个数.先理解一下概念,什么叫最大公约数.就是12有很多个因数,16也有很多个因数,这两堆因数中有一些重合的因数,在这些重合的因数中找到那个最大的.那么最大公约数一定 ...
- logback 中文手册
摘自:http://aub.iteye.com/blog/1896611 logback 中文手册 博客分类: Log loglogbackloback手册loback中文手册 logback 常 ...
- spark源码阅读之network(3)
TransportContext用来创建TransportServer和TransportclientFactory,同时使用TransportChannelHandler用来配置channel的pi ...
- PopupWindow简单使用(一)
1.构造函数 //方法一: public PopupWindow (Context context) //方法二: public PopupWindow(View conten ...
- 微信运动数据抓取(Python)
"微信运动"能够向朋友分享一个包含有运动数据的网页,网页中就有我们需要的数据.url类似于:http://hw.weixin.qq.com/steprank/step/person ...
- angular 新建组件
创建组件 ng g component componentName 第一步:引入其他组件 ngFor指令与数据绑定(数据驱动视图) 父组件穿值到自组建
- 巧用Scrum与Kanban
本文来自网易云社区 文\屈鹏飞 在互联网行业的项目管理实践中,敏捷和精益一直是大家所提倡的思想,其中Scrum和Kanban方法作为即敏捷又精益的典型代表,许多PM都在研究,笔者近期也在学习和实施Sc ...
- Kotlin 区间的一些小注意
1:步进 step 在kotlin 中区间通过循环可以实现每隔几个输出. 比如1..100,我每隔3个输出: fun main(args:Array<Stting>) { .. step) ...