Kosaraju 算法检测有向图的强连通性

简介:

给定一个有向图 G = (V, E) ,对于任意一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的,则说明该图 G 是强连通的(Strongly Connected)。如下图中,任意两个顶点都是互相可达的。

对于无向图,判断图是否是强连通的,可以直接使用深度优先搜索(DFS)广度优先搜索(BFS),从任意一个顶点出发,如果遍历的结果包含所有的顶点,则说明图是强连通的。

而对于有向图,则不能使用 DFS 或 BFS 进行直接遍历来判断。如下图中,如果从顶点 0 开始遍历则可判断是强连通的,而如果从其它顶点开始遍历则无法抵达所有节点。

那么,该如何判断有向图的强连通性呢?

实际上,解决该问题的较好的方式就是使用强连通分支算法(SCC:Strongly Connected Components),可以在 O(V+E) 时间内找到所有的 SCC。如果 SCC 的数量是 1,则说明整个图是强连通的。

有向图 G = (V, E) 的一个强连通分支是一个最大的顶点集合 C,C 是 V 的子集,对于 C 中的每一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的。

实现 SCC 的一种算法就是 Kosaraju 算法。Kosaraju 算法基于深度优先搜索(DFS),并对图进行两次 DFS 遍历,算法步骤如下:

  1. 初始化设置所有的顶点为未访问的;
  2. 从任意顶点 v 开始进行 DFS 遍历,如果遍历结果没有访问到所有顶点,则说明图不是强连通的;
  3. 置换整个图(Reverse Graph);
  4. 设置置换后的图中的所有顶点为未访问过的;
  5. 从与步骤 2 中相同的顶点 v 开始做 DFS 遍历,如果遍历没有访问到所有顶点,则说明图不是强连通的,否则说明图是强连通的。

Kosaraju 算法的思想就是,如果从顶点 v 可以抵达所有顶点,并且所有顶点都可以抵达 v,则说明图是强连通的。

复制代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 
  5 namespace GraphAlgorithmTesting
  6 {
  7   class Program
  8   {
  9     static void Main(string[] args)
 10     {
 11       Graph g = new Graph(5);
 12       g.AddEdge(0, 1, 11);
 13       g.AddEdge(1, 2, 13);
 14       g.AddEdge(2, 3, 10);
 15       g.AddEdge(3, 0, 12);
 16       g.AddEdge(2, 4, 4);
 17       g.AddEdge(4, 2, 14);
 18 
 19       Console.WriteLine();
 20       Console.WriteLine("Graph Vertex Count : {0}", g.VertexCount);
 21       Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount);
 22       Console.WriteLine();
 23 
 24       Console.WriteLine("Is graph strongly connected: {0}", g.Kosaraju());
 25 
 26       Console.ReadKey();
 27     }
 28 
 29     class Edge
 30     {
 31       public Edge(int begin, int end, int weight)
 32       {
 33         this.Begin = begin;
 34         this.End = end;
 35         this.Weight = weight;
 36       }
 37 
 38       public int Begin { get; private set; }
 39       public int End { get; private set; }
 40       public int Weight { get; private set; }
 41 
 42       public override string ToString()
 43       {
 44         return string.Format(
 45           "Begin[{0}], End[{1}], Weight[{2}]",
 46           Begin, End, Weight);
 47       }
 48     }
 49 
 50     class Graph
 51     {
 52       private Dictionary<int, List<Edge>> _adjacentEdges
 53         = new Dictionary<int, List<Edge>>();
 54 
 55       public Graph(int vertexCount)
 56       {
 57         this.VertexCount = vertexCount;
 58       }
 59 
 60       public int VertexCount { get; private set; }
 61 
 62       public IEnumerable<int> Vertices { get { return _adjacentEdges.Keys; } }
 63 
 64       public IEnumerable<Edge> Edges
 65       {
 66         get { return _adjacentEdges.Values.SelectMany(e => e); }
 67       }
 68 
 69       public int EdgeCount { get { return this.Edges.Count(); } }
 70 
 71       public void AddEdge(int begin, int end, int weight)
 72       {
 73         if (!_adjacentEdges.ContainsKey(begin))
 74         {
 75           var edges = new List<Edge>();
 76           _adjacentEdges.Add(begin, edges);
 77         }
 78 
 79         _adjacentEdges[begin].Add(new Edge(begin, end, weight));
 80       }
 81 
 82       public bool Kosaraju()
 83       {
 84         // Step 1: Mark all the vertices as not visited (For first DFS)
 85         bool[] visited = new bool[VertexCount];
 86         for (int i = 0; i < visited.Length; i++)
 87           visited[i] = false;
 88 
 89         // Step 2: Do DFS traversal starting from first vertex.
 90         DFS(0, visited);
 91 
 92         // If DFS traversal doesn’t visit all vertices, then return false.
 93         for (int i = 0; i < VertexCount; i++)
 94           if (visited[i] == false)
 95             return false;
 96 
 97         // Step 3: Create a reversed graph
 98         Graph reversedGraph = Transpose();
 99 
100         // Step 4: Mark all the vertices as not visited (For second DFS)
101         for (int i = 0; i < visited.Length; i++)
102           visited[i] = false;
103 
104         // Step 5: Do DFS for reversed graph starting from first vertex.
105         // Staring Vertex must be same starting point of first DFS
106         reversedGraph.DFS(0, visited);
107 
108         // If all vertices are not visited in second DFS, then
109         // return false
110         for (int i = 0; i < VertexCount; i++)
111           if (visited[i] == false)
112             return false;
113 
114         return true;
115       }
116 
117       void DFS(int v, bool[] visited)
118       {
119         visited[v] = true;
120 
121         if (_adjacentEdges.ContainsKey(v))
122         {
123           foreach (var edge in _adjacentEdges[v])
124           {
125             if (!visited[edge.End])
126               DFS(edge.End, visited);
127           }
128         }
129       }
130 
131       Graph Transpose()
132       {
133         Graph g = new Graph(this.VertexCount);
134 
135         foreach (var edge in this.Edges)
136         {
137           g.AddEdge(edge.End, edge.Begin, edge.Weight);
138         }
139 
140         return g;
141       }
142     }
143   }
144 }
复制代码

参考资料







本文转自匠心十年博客园博客,原文链接:http://www.cnblogs.com/gaochundong/p/kosaraju_check_directed_graph_stronly_connected.html,如需转载请自行联系原作者

目录
相关文章
|
3月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于MSER和HOG特征提取的SVM交通标志检测和识别算法matlab仿真
### 算法简介 1. **算法运行效果图预览**:展示算法效果,完整程序运行后无水印。 2. **算法运行软件版本**:Matlab 2017b。 3. **部分核心程序**:完整版代码包含中文注释及操作步骤视频。 4. **算法理论概述**: - **MSER**:用于检测显著区域,提取图像中稳定区域,适用于光照变化下的交通标志检测。 - **HOG特征提取**:通过计算图像小区域的梯度直方图捕捉局部纹理信息,用于物体检测。 - **SVM**:寻找最大化间隔的超平面以分类样本。 整个算法流程图见下图。
|
2月前
|
机器学习/深度学习 监控 算法
基于反光衣和检测算法的应用探索
本文探讨了利用机器学习和计算机视觉技术进行反光衣检测的方法,涵盖图像预处理、目标检测与分类、特征提取等关键技术。通过YOLOv5等模型的训练与优化,展示了实现高效反光衣识别的完整流程,旨在提升智能检测系统的性能,应用于交通安全、工地监控等领域。
|
2月前
|
JSON 算法 数据挖掘
基于图论算法有向图PageRank与无向图Louvain算法构建指令的方式方法 用于支撑qwen agent中的统计相关组件
利用图序列进行数据解读,主要包括节点序列分析、边序列分析以及结合节点和边序列的综合分析。节点序列分析涉及节点度分析(如入度、出度、度中心性)、节点属性分析(如品牌、价格等属性的分布与聚类)、节点标签分析(如不同标签的分布及标签间的关联)。边序列分析则关注边的权重分析(如关联强度)、边的类型分析(如管理、协作等关系)及路径分析(如最短路径计算)。结合节点和边序列的分析,如子图挖掘和图的动态分析,可以帮助深入理解图的结构和功能。例如,通过子图挖掘可以发现具有特定结构的子图,而图的动态分析则能揭示图随时间的变化趋势。这些分析方法结合使用,能够从多个角度全面解读图谱数据,为决策提供有力支持。
120 0
|
3月前
|
算法 安全
分别使用OVP-UVP和OFP-UFP算法以及AFD检测算法实现反孤岛检测simulink建模与仿真
本课题通过Simulink建模与仿真,实现OVP-UVP、OFP-UFP算法及AFD检测算法的反孤岛检测。OVP-UVP基于电压幅值变化,OFP-UFP基于频率变化,而AFD则通过注入频率偏移信号来检测孤岛效应,确保电力系统安全稳定运行。系统使用MATLAB 2013b进行建模与仿真验证。
|
2月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于GA-PSO-SVM算法的混沌背景下微弱信号检测matlab仿真
本项目基于MATLAB 2022a,展示了SVM、PSO、GA-PSO-SVM在混沌背景下微弱信号检测中的性能对比。核心程序包含详细中文注释和操作步骤视频。GA-PSO-SVM算法通过遗传算法和粒子群优化算法优化SVM参数,提高信号检测的准确性和鲁棒性,尤其适用于低信噪比环境。
|
2月前
|
存储 JSON 算法
TDengine 检测数据最佳压缩算法工具,助你一键找出最优压缩方案
在使用 TDengine 存储时序数据时,压缩数据以节省磁盘空间是至关重要的。TDengine 支持用户根据自身数据特性灵活指定压缩算法,从而实现更高效的存储。然而,如何选择最合适的压缩算法,才能最大限度地降低存储开销?为了解决这一问题,我们特别推出了一个实用工具,帮助用户快速判断并选择最适合其数据特征的压缩算法。
67 0
|
3月前
|
算法 计算机视觉 Python
圆形检测算法-基于颜色和形状(opencv)
该代码实现了一个圆检测算法,用于识别视频中的红色、白色和蓝色圆形。通过将图像从RGB转换为HSV颜色空间,并设置对应颜色的阈值范围,提取出目标颜色的区域。接着对这些区域进行轮廓提取和面积筛选,使用霍夫圆变换检测圆形,并在原图上绘制检测结果。
108 0
|
5月前
|
机器学习/深度学习 监控 算法
目标检测算法技术
8月更文挑战第11天
|
5月前
|
机器学习/深度学习 监控 算法
目标检测算法
8月更文挑战第5天
|
5月前
|
机器学习/深度学习 监控 算法
目标检测算法
8月更文挑战第8天