在了解kosaraju算法之前我们先了解一下什么是强连通分量,在有向图中如果两个定点vi,ui存在一条路劲从vi到达ui且也存在一条路劲从ui到达vi那么由ui和vi这两个点构成的图成为强连通图,简洁一点就是存在两个或两个点以它们之间可以相互可达由这些点构成的图就称之为强连通图它们的存在形式可以如下

当然一个点也是一个强连通分量,它们都满足所有点之间都可以互相可达。

以上就是对强连通分量的介绍接下来对kosaraju算法思路进行分析。

我们将对下面这个图进行对kosaraju算法进行解析:

我们可以发现此图存在两个强联通分量它们分别是,强连通分量A:1,3,2; 强连通分量B:5,4,6。

kosaraju的主要思想就是图进行两边dfs但是第二遍dfs的图必须是与原图相反的图,然后将第一遍的dfs比例的顺序用栈存起来然后再用栈内的元素对原图的反向图进行遍历最后就可以求得强连通分量。

Q:为什么要跑两边dfs?

A:kosaraju主要还是介于dfs遍历原理上,对于上图的dfs遍历我们假设以点1作为起点所以我们可以的的dfs遍历序为下图中绿色的回溯的点push进入栈中

所以栈内的值为1,3,5,4,6,2。

当以点1为起点进行dfs搜索我们会从点1搜到点6并不能确定强连通分量的元素但是当我们将原图反向建图再跑dfs的时候我们会发现每个强连通分量都可以分开了

为什么?我们将用图解释:

原图反图的建立,我们可以发下当我们把原图反向建立时,我们可以发现由3-->5这条边变成了5-->3这条边,当我们再以点1为起点进行dfs时我们可以发现与之前不同点1不能遍历完全部节点

因此第二遍dfs跑原图的反图时我们就将两个强连通分量给分开了,正好在第一遍dfs我们就将正图的dfs序存入栈中,那我们在第二遍dfs的时候我们只需要将栈中的元素取出跑一边反向图即可

求得强连通分量。

上面这个图我们可以手推得到,强连通分量1:  1,3,2;   强连通分量2:  5,4,6。

代码:
第一遍dfs跑正图将图的dfs序存入栈中:

  1. void dfs1(int x)
  2. {
  3. if(vis[x]) return;
  4. vis[x]=true;
  5. for(int i=;i<vt[x].size();i++)
  6. dfs1(vt[x][i]);
  7. z.push(x);
  8. return;
  9. }

第二遍dfs跑一边反着的原图:

  1. void dfs2(int x)
  2. {
  3. for(int i=;i<rvt[x].size();i++)
  4. {
  5. if(vis[rvt[x][i]]) continue;
  6. vis[rvt[x][i]]=true;
  7. dfs2(rvt[x][i]);
  8. out<<rvt[x][i]<<" ";
  9. }
  10. return;
  11. }
  12. void scc_find()
  13. {
  14. memset(vis,false,sizeof(vis));//跑第二遍dfs的时候vis标记数组一定要初始化为false
  15. while(!z.empty())//对栈内的元素进行dfs寻找强连通分量
  16. {
  17. int t=z.top();
  18. z.pop();
  19. if(vis[t]) continue;
  20. vis[t]=true;
  21. scc++;
  22. out<<"group:"<<t<<" ";
  23. dfs2(t);
  24. out<<endl;
  25. }
  26. return;
  27. }

完整代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <iomanip>
  5. #include <stack>
  6. #include <vector>
  7. using namespace std;
  8. #define in cin
  9. #define out cout
  10. typedef long long insert;
  11. const int N=2e5+;
  12. stack<int> z;
  13. vector<int> vt[N];
  14. vector<int> rvt[N];
  15. insert n,m,x,y,scc;
  16. bool vis[N];
  17. void inital_value()
  18. {
  19. for(int i=;i<=m;i++)
  20. {
  21. in>>x>>y;
  22. vt[x].push_back(y);
  23. rvt[y].push_back(x);//反向存图
  24. }
  25. return;
  26. }
  27. void dfs1(int x)
  28. {
  29. if(vis[x]) return;
  30. vis[x]=true;
  31. for(int i=;i<vt[x].size();i++)
  32. dfs1(vt[x][i]);
  33. z.push(x);
  34. return;
  35. }
  36. void dfs2(int x)
  37. {
  38. for(int i=;i<rvt[x].size();i++)
  39. {
  40. if(vis[rvt[x][i]]) continue;
  41. vis[rvt[x][i]]=true;
  42. dfs2(rvt[x][i]);
  43. out<<rvt[x][i]<<" ";
  44. }
  45. return;
  46. }
  47. void scc_find()
  48. {
  49. memset(vis,false,sizeof(vis));//跑第二遍dfs的时候vis标记数组一定要初始化为false
  50. while(!z.empty())//对栈内的元素进行dfs寻找强连通分量
  51. {
  52. int t=z.top();
  53. z.pop();
  54. if(vis[t]) continue;
  55. vis[t]=true;
  56. scc++;
  57. out<<"group:"<<t<<" ";
  58. dfs2(t);
  59. out<<endl;
  60. }
  61. return;
  62. }
  63. int main()
  64. {
  65. in>>n>>m;
  66. inital_value();
  67. for(int i=;i<=n;i++)
  68. {
  69. if(vis[i]) continue;
  70. dfs1(i);
  71. }
  72. scc_find();
  73. out<<"强连通分量总数"<<endl;
  74. out<<scc<<endl;
  75. return ;
  76. }

kosaraju求强连通分量的更多相关文章

  1. kosaraju算法求强连通分量

    什么是强连通分量?在这之前先定义一个强连通性(strong connectivity)的概念:有向图中,如果一个顶点s到t有一条路径,t到s也有一条路径,即s与t互相可达,那么我们说s与t是强连通的. ...

  2. UESTC 901 方老师抢银行 --Tarjan求强连通分量

    思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个D ...

  3. poj 2186 tarjan求强连通分量

    蕾姐讲过的例题..玩了两天后才想起来做 貌似省赛之后确实变得好懒了...再努力两天就可以去北京玩了! 顺便借这个题记录一下求强连通分量的算法 1 只需要一次dfs 依靠stack来实现的tarjan算 ...

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

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

  5. [Uva247][Tarjan求强连通分量][Calling Circles]

    题目大意: 例如:A跟B打电话,B跟C打电话,C跟A打电话..D跟E打电话,E跟D不打电话.则A,B,C属于同一个电话圈,D,E分别属于一个电话圈,问有多少个电话圈. 分析 就是裸的求强连通分量,直接 ...

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

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

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

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

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

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

  9. HDU 1827 Summer Holiday(tarjan求强连通分量+缩点构成新图+统计入度+一点贪心思)经典缩点入门题

    Summer Holiday Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

随机推荐

  1. 解决MyEclipse JAVA EE无法识别Base64问题

    第一步:右击项目选择Build Path,选择Configure Build Path 第二步:点击JRE System Library选择右边的Edit 第三步:选择Alternate JRE,点击 ...

  2. 解决 LLVM 错误 cannot specify -o when generating multiple output files

    Xcode 9 使用 LLVM 混淆器会提示错误: clang: error: cannot specify -o when generating multiple output files 通过对比 ...

  3. 生成Ipa安装包的plist文件后生成下载链接

    假设生成的plist文件的下载链接是: https://www.xx.com/download/xx.plist 那么如果想让苹果手机的浏览器点击后开始下载苹果软件包,则网页中的下载链接需要拼接成 i ...

  4. C语言#ifdef等宏的妙用

    这几个宏是为了进行条件编译.一般情况下,源程序中所有的行都参加编译.但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”.有时,希望当满足某条件 ...

  5. verilog中参数传递与参数定义中#的作用(二)

    一.module内部有效的定义 用parameter来定义一个标志符代表一个常量,称作符号常量,他可以提高程序的可读性和可维护性.parameter是参数型数据的关键字,在每一个赋值语句的右边都必须是 ...

  6. [POJ1014]Dividing(二进制优化多重背包)

    #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int ...

  7. 阿里云 Debian 9.2 安装 Java Web 环境

    CentOS 源内包太旧,和本地开发环境不兼容的地方太多 系统配置 更新数据库与软件包 # apt-get update && apt-get -y upgrade 提示是否保留本地已 ...

  8. WPF ResourceDictionary 主题资源替换

    原文:WPF ResourceDictionary 主题资源替换 当我们需要在程序中替换主题,更换另一套背景.颜色.样式时,如何在不修改资源Key值,直接替换呢? 问题&疑问 1. Key值冲 ...

  9. 使用putty远程登录Ubuntu时,报Network error:Connection refused错误及解决

    putty远程登录Ubuntu,弹出Network error:Connection refused的错误提示框,就是因为Ubuuntu没有安装ssh服务. 执行命令: sudo apt instal ...

  10. logger 配置文件详解

    Logback配置文件详解 Logback,Java 日志框架. Logback 如何加载配置的 logback 首先会查找 logback.groovy 文件 当没有找到,继续试着查找 logbac ...