强连通分量(tarjan求强连通分量)
双DFS方法就是正dfs扫一遍,然后将边反向dfs扫一遍。《挑战程序设计》上有说明。
双dfs代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 6 using namespace std; 7 const int MAXN = 1e4 + 5; 8 vector <int> G[MAXN]; //图的邻接表 9 vector <int> RG[MAXN]; //图的反向邻接表 10 vector <int> vs; //后序遍历的顶点顺序表 11 bool ok[MAXN]; //访问标记 12 int node[MAXN]; //所属强连通分量的序号 13 //第一次dfs 14 void dfs(int u) { 15 ok[u] = true; 16 for(int i = 0 ; i < G[u].size() ; i++) { 17 if(!ok[G[u][i]]) 18 dfs(G[u][i]); 19 } 20 vs.push_back(u); 21 } 22 //第二次dfs 23 void rdfs(int u , int k) { 24 node[u] = k; 25 ok[u] = true; 26 for(int i = 0 ; i < RG[u].size() ; i++) { 27 if(!ok[RG[u][i]]) 28 rdfs(RG[u][i] , k); 29 } 30 } 31 32 int main() 33 { 34 int n , m , u , v; 35 while(~scanf("%d %d" , &n , &m) && (n || m)) { 36 for(int i = 1 ; i <= n ; i++) { 37 G[i].clear(); 38 RG[i].clear(); 39 ok[i] = false; 40 vs.clear(); 41 } 42 for(int i = 0 ; i < m ; i++) { 43 scanf("%d %d" , &u , &v); 44 G[u].push_back(v); 45 RG[v].push_back(u); 46 } 47 //第一次dfs 选取任意的顶点作为起点遍历 后序遍历 越接近图尾部(叶子)的顶点顺序越小 48 for(int i = 1 ; i <= n ; i++) { 49 if(!ok[i]) 50 dfs(i); 51 } 52 memset(ok , false , sizeof(ok)); 53 int k = 0; 54 //第二次dfs 将边反向遍历 以标记最大的顶点作为起点遍历 这样便可以给强连通分量标号 55 for(int i = vs.size() - 1 ; i >= 0 ; i--) { 56 if(!ok[vs[i]]) 57 rdfs(vs[i] , ++k); 58 } 59 if(k > 1) { 60 printf("No\n"); 61 } 62 else { 63 printf("Yes\n"); 64 } 65 } 66 }
tarjan代码虽然比双dfs多,理解也稍微复杂,但是用处比较多,像求LCA 桥 scc之类的问题。
推荐一个学scc的blog,讲的很好。 https://www.byvoid.com/blog/tag/%E5%9C%96%E8%AB%96
代码如下:
1 //以hdu1269为例 2 //强连通分量 tarjan算法 3 #include <iostream> 4 #include <cstdio> 5 #include <cstring> 6 #include <vector> 7 using namespace std; 8 const int MAXN = 1e4 + 5; 9 vector <int> G[MAXN]; //临接表 10 bool instack[MAXN]; //i是否还在在栈里 11 int sccnum , index; //连通分量数 和时间顺序 12 int top , st[MAXN]; //存储i的模拟栈 13 int block[MAXN]; //i所属的连通分量 14 int low[MAXN] , dfn[MAXN]; //i能最早访问到的点 和时间戳 15 16 void tarjan(int u) { 17 st[++top] = u; 18 instack[u] = true; 19 low[u] = dfn[u] = ++index; 20 for(int i = 0 ; i < G[u].size() ; i++) { 21 int v = G[u][i]; 22 if(!dfn[v]) { //v点没访问过 23 tarjan(v); 24 if(low[v] < low[u]) { //回溯上来 low[v]表示的时间戳(连通分量的根) u和v在一个连通分量里 25 low[u] = low[v]; 26 } 27 } 28 else if(instack[v]) { //v还在栈里 说明u和v在一个连通分量(形成环路) v相当于连通分量的一个根 29 low[u] = min(low[u] , dfn[v]); 30 } 31 } 32 int v; 33 if(dfn[u] == low[u]) { //是连通分量的根 34 sccnum++; 35 do { 36 v = st[top--]; 37 block[v] = sccnum; 38 instack[v] = false; 39 }while(v != u); //连通分量的所有的点 40 } 41 } 42 43 void init(int n) { 44 for(int i = 1 ; i <= n ; i++) { 45 G[i].clear(); 46 instack[i] = false; 47 dfn[i] = 0; 48 } 49 sccnum = index = top = 0; 50 } 51 52 int main() 53 { 54 int n , m , u , v; 55 while(~scanf("%d %d" , &n , &m) && (n || m)) { 56 init(n); 57 for(int i = 0 ; i < m ; i++) { 58 scanf("%d %d" , &u , &v); 59 G[u].push_back(v); 60 } 61 for(int i = 1 ; i <= n ; i++) { 62 if(!dfn[i]) { 63 tarjan(i); 64 } 65 } 66 if(sccnum > 1) { 67 cout << "No\n"; 68 } 69 else { 70 cout << "Yes\n"; 71 } 72 } 73 }
转载于:https://www.cnblogs.com/Recoder/p/5247992.html
强连通分量(tarjan求强连通分量)相关推荐
- HDU-1269 Tarjan求强连通分量,模板题
HDU 1269 题意:n个点m条单向边,问任意两个点是否连通. 总结:参考大神博客码的,有些地方还是不太明白. 而且这题还可以双向dfs做,有时间再做一下. // HDU-1269 #include ...
- hdu 1269 tarjan求强连通分量
tarjan求强连通分量的裸题复习,可当做模板. 1 #include <stack> 2 #include <cstdio> 3 #include <cstring&g ...
- The King’s Problem(tarjan求强连通分量缩点+匈牙利求有向无环图的最小路径覆盖)
Link:http://acm.hdu.edu.cn/showproblem.php?pid=3861 The King's Problem Time Limit: 2000/1000 MS (Jav ...
- 洛谷 P2921 在农场万圣节Trick or Treat on the Farm (tarjan求强连通分量)
洛谷 P2921 在农场万圣节Trick or Treat on the Farm (tarjan求强连通分量) 题目描述 每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N&l ...
- hdu 1269(Tarjan求强连通分量)
这道题目就是求强连通分量... 这里采用的是Tarjan算法:http://m.blog.csdn.net/blog/qq574857122/16361033 AC代码: #include<io ...
- Tarjan求强连通分量
[算法定义] 在有向图中,如果两个顶点至少存在一条路径(可以相互通达),则称两个顶点强连通(strongly connected). 如果有向图G的每两个顶点都强连通,称G是一个强连通图. 非强连通有 ...
- P1262 间谍网络 (Tarjan 求强连通分量)
题目传送门:https://www.luogu.com.cn/problem/P1262 题意 题意转换成图的角度理解,给出初始可以访问的节点 D i D_i Di 以及访问这些节点需要的代价 W ...
- 【HDU - 4635】Strongly connected(缩点,新图性质,建图,Tarjan求强连通分量)
题干: Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the ...
- 图论 —— 图的连通性 —— Tarjan 求强连通分量
[概述] Tarjan 算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树. 搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量. [ ...
- tarjan求强连通分量的思考
我是按照这里的思路来的.这个博文只是感性理解. 递归树 关于递归树,这篇博文讲的很好,我只是给自己总结一下. 定义vis数组,在dfs连通图时赋予它们不同的含义: vis=0,表示这个点没有被访问. ...
最新文章
- Python--切片学习记录
- Error: Network is unreachable. Reason: couldn‘t connect to server localhost:27017(连接mongodb数据库失败)
- SpringMVC框架--学习笔记(上)
- opencv计算brox光流_字节跳动计算机视觉算法实习生视频面试
- 【opencv】图像细化
- 硬件:RS232基础知识笔记
- 建立能持续处理请求的Server端改造
- android 运行jquery,Android端JQueryMobile使用教程(一)
- Centos7 minmal 安装
- Git学习总结(23)——Git commit message和版本管理规范总结
- VB连接oracle数据库
- WinDbg分析蓝屏dump原因
- Payment支付平台API接口文档
- 老路用得上的商学课-61-80学习(读书)笔记
- 忘记windows密码怎么办,教你五招!
- 使用jib发布代码流程
- AR涂涂乐项目之识别图制作制作地球仪线框一
- SimpleApp例程中两种绑定机制程序流程
- 个人对软件工程的期望及个人目标
- 一文速学-Pandas处理时间序列数据操作详解
热门文章
- tpch测试mysql_MySQL数据库之MySQL-tpch 测试工具简要手册
- 依赖注入(DI)入门
- Kafka高可用机制入门
- Dstream的action算子与RDD的action算子
- Opencv学习笔记_计算机视觉是什么?Opencv的起源
- JavaScript的apply和call方法及其区别
- 问题:子进程父进程哪个先执行:【转】关于 fork 和父子进程的理解
- 《HTML5 开发实例大全》——1.32 在表单中使用 object 元素插入一个Flash
- UIButton的resizableImageWithCapInsets使用解析
- CXF开发WebService服务器端