双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求强连通分量)相关推荐

  1. HDU-1269 Tarjan求强连通分量,模板题

    HDU 1269 题意:n个点m条单向边,问任意两个点是否连通. 总结:参考大神博客码的,有些地方还是不太明白. 而且这题还可以双向dfs做,有时间再做一下. // HDU-1269 #include ...

  2. hdu 1269 tarjan求强连通分量

    tarjan求强连通分量的裸题复习,可当做模板. 1 #include <stack> 2 #include <cstdio> 3 #include <cstring&g ...

  3. 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 ...

  4. 洛谷 P2921 在农场万圣节Trick or Treat on the Farm (tarjan求强连通分量)

    洛谷 P2921 在农场万圣节Trick or Treat on the Farm (tarjan求强连通分量) 题目描述 每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N&l ...

  5. hdu 1269(Tarjan求强连通分量)

    这道题目就是求强连通分量... 这里采用的是Tarjan算法:http://m.blog.csdn.net/blog/qq574857122/16361033 AC代码: #include<io ...

  6. Tarjan求强连通分量

    [算法定义] 在有向图中,如果两个顶点至少存在一条路径(可以相互通达),则称两个顶点强连通(strongly connected). 如果有向图G的每两个顶点都强连通,称G是一个强连通图. 非强连通有 ...

  7. P1262 间谍网络 (Tarjan 求强连通分量)

    题目传送门:https://www.luogu.com.cn/problem/P1262 题意 题意转换成图的角度理解,给出初始可以访问的节点 D i D_i Di​ 以及访问这些节点需要的代价 W ...

  8. 【HDU - 4635】Strongly connected(缩点,新图性质,建图,Tarjan求强连通分量)

    题干: Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the ...

  9. 图论 —— 图的连通性 —— Tarjan 求强连通分量

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

  10. tarjan求强连通分量的思考

    我是按照这里的思路来的.这个博文只是感性理解. 递归树 关于递归树,这篇博文讲的很好,我只是给自己总结一下. 定义vis数组,在dfs连通图时赋予它们不同的含义: vis=0,表示这个点没有被访问. ...

最新文章

  1. Python--切片学习记录
  2. Error: Network is unreachable. Reason: couldn‘t connect to server localhost:27017(连接mongodb数据库失败)
  3. SpringMVC框架--学习笔记(上)
  4. opencv计算brox光流_字节跳动计算机视觉算法实习生视频面试
  5. 【opencv】图像细化
  6. 硬件:RS232基础知识笔记
  7. 建立能持续处理请求的Server端改造
  8. android 运行jquery,Android端JQueryMobile使用教程(一)
  9. Centos7 minmal 安装
  10. Git学习总结(23)——Git commit message和版本管理规范总结
  11. VB连接oracle数据库
  12. WinDbg分析蓝屏dump原因
  13. Payment支付平台API接口文档
  14. 老路用得上的商学课-61-80学习(读书)笔记
  15. 忘记windows密码怎么办,教你五招!
  16. 使用jib发布代码流程
  17. AR涂涂乐项目之识别图制作制作地球仪线框一
  18. SimpleApp例程中两种绑定机制程序流程
  19. 个人对软件工程的期望及个人目标
  20. 一文速学-Pandas处理时间序列数据操作详解

热门文章

  1. tpch测试mysql_MySQL数据库之MySQL-tpch 测试工具简要手册
  2. 依赖注入(DI)入门
  3. Kafka高可用机制入门
  4. Dstream的action算子与RDD的action算子
  5. Opencv学习笔记_计算机视觉是什么?Opencv的起源
  6. JavaScript的apply和call方法及其区别
  7. 问题:子进程父进程哪个先执行:【转】关于 fork 和父子进程的理解
  8. 《HTML5 开发实例大全》——1.32 在表单中使用 object 元素插入一个Flash
  9. UIButton的resizableImageWithCapInsets使用解析
  10. CXF开发WebService服务器端