Tarjan's algorithm
Tarjan算法可以用来求有向图的强连通分量个数,之前十分粗略的写了Kosaraju算法,这里打算比较认真的分析一下Tarjan算法,然后给出算法实现代码。
Tarjan算法的主要算法部分也是dfs(深度优先搜索),但利用了重要的额外信息。下面详细分析一下算法执行过程。
再强调一个强连通子图的重要特点:对于强连通子图,有一个特定的事实就是,该子图一定形成环,那么从该子图中任意点出发,总能回到出发点。
基于上面这一点,Tarjan算法通过维护两个存放顶点访问顺序(时间)的数组。如果子图形成环,则将处于环中的每一个顶点的访问顺序置为该环的出发点的访问时间,以表明他们是一个强连通子图。可能你会怀疑进入环后,不会只在环中遍历,可能会跳到其他顶点上。实际上这担心是多余,因为图结构使用邻接链表表示,强连通子图使用dfs进行遍历时,只会寻找与当前顶点连接的出度顶点,而形成环的子图中,会很合理的按顺序遍历完。对于孤立点,则自身就是一个环,即强连通分量。
这就是Tarjan算法的思想,主要的就是维护的两个存储访问顺序的数组,然后,形成环的节点的访问时间都置为该强连通子图的出发点的访问时间。
通过下图可以更直观的理解Tarjan算法的执行过程(图来自维基):

时间复杂度分析:
最坏情况是图G的强连通子图就是其本身(这样的图称为强连通图),这时dfs的消费为 $ O(|V| + |E|) $,最后一次dfs的while循环再消费掉 $ O(V) $,所以dfs()最坏情况为 $ O(|V| + |E|) $。最后tarjan()的总消耗为 $ O (V^2) $。
空间复杂度:
显然 $ O(V) $。
算法实现:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stack>
#include <list>
#include <minmax.h>
using namespace std;
const int N = 10010;
list<int> *adj;
stack<int> s;
int vis[N], low[N];
bool onstack[N];
int times = 0, scc = 0;
void addEdge(int u, int v)
{
adj[u].push_back(v);
}
void dfs(int u)
{
vis[u] = low[u] = times++;
s.push(u);
onstack[u] = true;
for (list<int>::iterator i = adj[u].begin(); i != adj[u].end(); ++i)
{
int v = *i;
if (vis[v] == -1)
{
dfs(v);
low[u] = min(low[u], low[v]);
}
else if (onstack[v] == true)
low[u] = min(low[u], vis[v]);
}
if (low[u] == vis[u])
{
while (s.top() != u)
{
int w = s.top();
cout << w << ' ';
onstack[w] = false;
s.pop();
}
int w = s.top();
cout << w << endl;
onstack[w] = false;
s.pop();
scc++;
}
}
void tarjan(int V, int E)
{
adj = new list<int>[V + 1];
list<int> v;
for (int i = 1; i <= V; i++)
{
vis[i] = low[i] = -1;
onstack[i] = false;
}
for (int i = 1; i <= E; i++)
{
int u, w;
cin >> u >> w;
adj[u].push_back(w);
}
for (int i = 1; i <= V; i++)
if (vis[i] == -1)
dfs(i);
cout << "该图的强连通分量个数为:" << scc << endl;
}
int main(int argc, char **argv)
{
int V, E;
cin >> V >> E;
tarjan(V, E);
return 0;
}
代码中dfs()函数的for循环后面的部分用来输出所有强连通子图中的顶点,并求出scc(Strongly Connected Components)个数。
下面以前面wiki图为例测试一下算法。
算法测试结果:
3 2 1
7 6
5 4
8
该图的强连通分量个数为:4
参考:
1.https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
2.https://www.geeksforgeeks.org/tarjan-algorithm-find-strongly-connected-components/
Tarjan's algorithm的更多相关文章
- algorithm@ Strongly Connected Component
Strongly Connected Components A directed graph is strongly connected if there is a path between all ...
- Prim 最小生成树算法
Prim 算法是一种解决最小生成树问题(Minimum Spanning Tree)的算法.和 Kruskal 算法类似,Prim 算法的设计也是基于贪心算法(Greedy algorithm). P ...
- Kruskal 最小生成树算法
对于一个给定的连通的无向图 G = (V, E),希望找到一个无回路的子集 T,T 是 E 的子集,它连接了所有的顶点,且其权值之和为最小. 因为 T 无回路且连接所有的顶点,所以它必然是一棵树,称为 ...
- Kosaraju 算法检测有向图的强连通性
给定一个有向图 G = (V, E) ,对于任意一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的,则说明该图 G 是强连通的(Strong ...
- Kosaraju 算法查找强连通分支
有向图 G = (V, E) 的一个强连通分支(SCC:Strongly Connected Components)是一个最大的顶点集合 C,C 是 V 的子集,对于 C 中的每一对顶点 u 和 v, ...
- GO语言的开源库
Indexes and search engines These sites provide indexes and search engines for Go packages: godoc.org ...
- 210. Course Schedule II
题目: There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have ...
- Go语言(golang)开源项目大全
转http://www.open-open.com/lib/view/open1396063913278.html内容目录Astronomy构建工具缓存云计算命令行选项解析器命令行工具压缩配置文件解析 ...
- [转]Go语言(golang)开源项目大全
内容目录 Astronomy 构建工具 缓存 云计算 命令行选项解析器 命令行工具 压缩 配置文件解析器 控制台用户界面 加密 数据处理 数据结构 数据库和存储 开发工具 分布式/网格计算 文档 编辑 ...
随机推荐
- python3练习100题--024
因为过生日,好几天没做题了,有点松懈. 我要更加加油啦-为了打败现在每天都厌恶的生活! 原题链接:http://www.runoob.com/python/python-exercise-exampl ...
- SDF数据库
一.SDF数据库初探 SDF是一个标准缩略数据库格式.这个数据库包含扩展名为.sdf的文件并且以结构化文件格式进行数据存储.这些SDF文件通常用于在不同数据库应用之间移动数据.它允许一个用户将一个软件 ...
- OpenGL 3D拾取文章(转)
参考文章 深入探索3D拾取技术 OpenGL 3D拾取 射线和三角形的相交检测(ray triangle intersection test) 3D拾取的方法有两种 1.基于几何计算的射线-三角形相交 ...
- 剑指offer 面试题56. 数组中只出现一次的两个数字
题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 方法1:用set记录出现过的数字 class Solution { public: void F ...
- .net c# MVC提交表单的4种方法
https://blog.csdn.net/qingkaqingka/article/details/85047781
- 2.10 webdriver中 js 使用
来源: 使用Webdriver执行JS小结 http://lijingshou.iteye.com/blog/2018929 selenium常用的js总结 http://www.cnblogs. ...
- 爬山 启发式合并 / STL
题目 其实 Kano 曾经到过由乃山,当然这名字一看山主就是 Yuno 嘛.当年 Kano 看见了由乃山,内心突然涌出了一股杜甫会当凌绝顶,一览众山小的豪气,于是毅然决定登山. 但是 Kano 总是习 ...
- linux 内存,cpu占用最高进程查询
1. 可以使用一下命令查使用内存最多的10个进程 ps -aux | sort -k4nr | head -n 10 2. 可以使用一下命令查使用CPU最多的10个进程 ps -aux | sort ...
- c#项目使用webrtc的降噪模块方法
分离webrtc的降噪(Noise Suppression)部分 webrtc是Google开源的优秀音视频处理及传输代码库,其中包含了audio processing.video processin ...
- MyBatis(6)——分页的实现
分页的实现 a)通过mysql的分页查询语句: 说明:sql的分页语句格式为select * from aaa limit #{startIndex},#{pageSize} //---------- ...