变量解释:
low 指当前节点在同一强连通分量(或环)能回溯到的dfn最小的节点
dfn 指当前节点是第几个被搜到的节点(时间戳)
sta 栈
vis 是否在栈中
ans 指强连通分量的数量
top 栈顶

1.求强连通分量
定义:如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。

算法:在有向图中从一点(u)开始dfs,记录dfn,搜到一个已在栈中的点(v)时用dfn[v] (low[v]也行,但只有求强连通分量时可以别的只能用dfn[v]) 尝试更新low[u],并在回溯时更新沿路的点的low值,走到low值与dfn相同的点时记录这个强连通分量即可。
也就是说:在同一个强连通分量中所有点low值相同,也就是有一个代表点(代表点即所有点的low值即强连通分量中dfn值最小的点)
时间复杂度为O(E+V)

code

void tarjan(int u){dfn[u]=low[u]=++cnt;//初始化一点的dfn和lowsta[++top]=u,vis[u]=true;//入栈for(int i=head[u];i;i=edge[i].next){//邻接表int v=edge[i].to;if(!dfn[v]){//如果没走过tarjan(v);low[u]=min(low[u],low[v]);//回溯过程时low值传递}else if(vis[v]) low[u]=min(low[u],dfn[v]); //low[v]也行 用代表点更新}if(dfn[u]==low[u]) {//如果是代表点 记录并出栈ans++;//记录强连通分量个数while(sta[top]!=u){vis[sta[top]]=false;top--;}vis[sta[top]]=false;top--;}return ;
}

2.求无向图的割点与割边
割点:在无向图中,如果将一个点以及所有连接该点的边都去掉,图就不再连通,那么这个点就叫做这个图的一个割点。
割边:在无向图中,如果将一条边去掉,图就不再连通则称这条边为图的一个割边。

求割点:如果一个点(u)所连接的几个节点(v)的low值大或等于此节点(u)的dfn值时说明之后的节点(v)无法连接到比此点(u)更早的点上,则说明这个节点(u)是一个割点。PS:根节点需特判,当根节点在dfs树有两个或更多个子树时则说明根节点是割点

求割边:与割点类似,如果一个点(u)的dfn值大于(不能等于,否则不一定)和它连接的一个节点(v)的low值,则说明这条边(uv)为图的一个割边

变量解释:
sum 指总共有几个割点(边)

割点code

void cutpoint(int u){int fl=0;//为特判准备dfn[u]=low[u]=++cnt;//初始化for(int i=head[u];i;i=edge[i].next){//用邻接表,下同int v=edge[i].to;if(!dfn[v]){cutpoint(v);low[u]=min(low[u],low[v]);if(u!=root&&low[v]>=dfn[u]&&!cpoint[u]) sum++,cpoint[u]=1;//不是根节点&&v的low值>=u的dfn值&&此点没有算过if(u==root) fl++;//此时特判++}low[u]=min(low[u],dfn[v]); }if(fl>=2&&!cpoint[u]) sum++,cpoint[u]=1;//根节点若有两棵子树则是割点
}

割边code

void cutedge(int u,int f){dfn[u]=low[u]=++cnt;for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(!dfn[v]){cutedge(v,u);low[u]=min(low[u],low[v]);if(dfn[u]<low[v]) cedge[++sum]=i;//记录边的序号}else if(v!=f) low[u]=min(low[u],dfn[v]); //只有当v不是u的上一个节点时可行}
}

完整模板code:
ps:这里就不打注释了,核心就在上面的部分里

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;const int MAX=1000010;
int n,m,cnt,sum,root;
int head[MAX],low[MAX],dfn[MAX],cpoint[MAX],cedge[MAX];struct edg{int to,next,from;
}edge[MAX];void add(int x,int y){edge[++cnt].next=head[x];edge[cnt].from=x,edge[cnt].to=y;head[x]=cnt;
}void cutpoint(int u){int fl=0;dfn[u]=low[u]=++cnt;for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(!dfn[v]){cutpoint(v);low[u]=min(low[u],low[v]);if(u!=root&&low[v]>=dfn[u]&&!cpoint[u]) sum++,cpoint[u]=1;if(u==root) fl++;}low[u]=min(low[u],dfn[v]); }if(fl>=2&&!cpoint[u]) sum++,cpoint[u]=1;
}void cutedge(int u,int f){dfn[u]=low[u]=++cnt;for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(!dfn[v]){cutedge(v,u);low[u]=min(low[u],low[v]);if(dfn[u]<low[v]) cedge[++sum]=i;}else if(v!=f) low[u]=min(low[u],dfn[v]);}
}void mset(){memset(dfn,0,sizeof dfn);memset(low,0,sizeof low);cnt=sum=0;
}void find_cutpoint(){for(int i=1;i<=n;i++) if(!dfn[i]) {root=i;cutpoint(i);}printf("%d\n",sum);for(int i=1;i<=n;i++) if(cpoint[i]) printf("%d ",i);
}void find_cutedge(){for(int i=1;i<=n;i++) if(!dfn[i]) cutedge(i,0);printf("%d\n",sum);for(int i=1;i<=sum;i++) printf("%d %d\n",edge[cedge[i]].from,edge[cedge[i]].to);
}int main(){
//  freopen("testdata.txt","r",stdin);scanf("%d %d",&n,&m);for(int i=1;i<=m;i++){int a,b;scanf("%d %d",&a,&b);add(a,b);add(b,a);}find_cutedge();mset();find_cutpoint();return 0;
}

转载于:https://www.cnblogs.com/Menteur-Hxy/p/9248051.html

Tarjan算法 (强联通分量 割点 割边)相关推荐

  1. Tarjan的强联通分量

    求强联通分量有很多种. <C++信息学奥赛一本通>  中讲过一个dfs求强联通分量的算法Kosdaraju,为了骗字数我就待会简单的说说.然而我们这篇文章的主体是Tarjan,所以我肯定说 ...

  2. tarjan求强联通分量

    [概述] Tarjan 算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树. 搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量. [ ...

  3. BZOJ 2140 稳定婚姻(强联通分量判环)【BZOJ修复工程】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2140 是 hydro 的 BZOJ ...

  4. tarjan算法(强连通分量与割点)

    tarjan算法可以求有向图的割点割边强连通分量(还有一些奇奇怪怪的操作) 我只会割点和强连通分量,割边(和缩点)以后可能会加,如果是来看割边的话,现在跑还来得及.. (先来一张有向图叭) 用这张图, ...

  5. [vios1023]维多利亚的舞会3强联通分量tarjan

    题目链接:https://vijos.org/p/1023 最近在练强联通分量,当然学的是tarjan算法 而这一道题虽然打着难度为3,且是tarjan算法的裸题出没在vijos里面 但其实并不是纯粹 ...

  6. P3387-【模板】缩点【tarjan,强联通分量,DAGdp】

    正题 评测记录: https://www.luogu.org/recordnew/lists?uid=52918&pid=P3387 大意 一个有向图.每个点有权值,但每个值只能取一次,每条边 ...

  7. 关于强联通分量 的求法讨论

    这个讨论主要是关于 HA2006年最受欢迎的牛 的讨论 . 尽管这道题对于很多dalao来说都觉得是模板题,但是仍是值得思考的,因为我第一次写这道题的时候, 缩完点之后建图建错玄学跑dfs n^2做法 ...

  8. 强联通分量与双连通分量

    强联通分量 1.概念 在有向图G中,如果两点互相可达,则称这两个点强连通,如果G中任意两点互相可达,则称G是强连通图. 定理: 1.一个有向图是强连通的,当且仅当G中有一个回路,它至少包含每个节点一次 ...

  9. POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)

    [题意]: 有N个结点M条边的图,有Q次操作,每次操作在点x, y之间加一条边,加完E(x, y)后还有几个桥(割边),每次操作会累积,影响下一次操作. [思路]: 先用Tarjan求出一开始总的桥的 ...

最新文章

  1. Shiny平台构建与R包开发(三)——数据输出
  2. 了解在HCI部署VDI的优势
  3. 大规模神经网络最新文献综述:训练高效DNN、节省内存使用、优化器设计
  4. linux 修改IP, DNS 命令
  5. 关于list 数据类型 和 ndarray 数据类型获取索引的小坑
  6. 视频课程-1小时上手 Spring Boot 及 达梦数据库 做数据展示后端
  7. nxos启动的初始化和https访问nx-api
  8. 计算机网络技术与应用应用题,计算机网络技术与应用题库答案.pdf
  9. 0基础自学前端好,还是报班培训好?
  10. android权限检查
  11. C#泛型学习实例(简单易懂)
  12. 二十一、K8s集群设置3-HTTPS-Cert-manager
  13. Serverless 实战:3 分钟实现文本敏感词过滤
  14. Mac 中如何解压.bin文件
  15. 7-3 求分数序列前N项和 (15分)
  16. 关于在JS中引入JS文件的JQ方法
  17. Python第一周学习总结
  18. 网易历届笔试面试题整理大全
  19. Mac电脑启动出现空白屏幕的解决办法
  20. SVN各种错误提示产生原因及处理方法

热门文章

  1. 高度平衡树 -- AVL 树
  2. 阿里云云市场双11战报:30分钟破100万,单品销量暴涨300倍!
  3. 最新OpenSSL漏洞CCS注入及升级修复
  4. 《碟中谍4:幽灵协议》蓝光1080P 720P首发!!汤姆克鲁斯主演
  5. DB2基础学习一 DB2产品介绍
  6. Javascript 逗号“,”引发的血案
  7. DataObjects.NET -- A Excellent O/R Mapping Framework!
  8. The Intelligent Investor Feedback
  9. 陷入迷茫的时候怎么办呢?
  10. 在国外读phd 的时候和supervisor沟通的时候需要注意的点