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,如需转载请自行联系原作者

目录
相关文章
|
9天前
|
传感器 资源调度 算法
DDMA-MIMO雷达多子带相干累积目标检测算法——论文阅读
本文提出一种多子带相干累积(MSCA)算法,通过引入空带和子带相干处理,解决DDMA-MIMO雷达的多普勒模糊与能量分散问题。该方法在低信噪比下显著提升检测性能,实测验证可有效恢复目标速度,适用于车载雷达高精度感知。
64 4
DDMA-MIMO雷达多子带相干累积目标检测算法——论文阅读
|
4月前
|
机器学习/深度学习 运维 监控
实时异常检测实战:Flink+PAI 算法模型服务化架构设计
本文深入探讨了基于 Apache Flink 与阿里云 PAI 构建的实时异常检测系统。内容涵盖技术演进、架构设计、核心模块实现及金融、工业等多领域实战案例,解析流处理、模型服务化、状态管理等关键技术,并提供性能优化与高可用方案,助力企业打造高效智能的实时异常检测平台。
329 1
|
3月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
84 0
|
8月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于GRU网络的MQAM调制信号检测算法matlab仿真,对比LSTM
本研究基于MATLAB 2022a,使用GRU网络对QAM调制信号进行检测。QAM是一种高效调制技术,广泛应用于现代通信系统。传统方法在复杂环境下性能下降,而GRU通过门控机制有效提取时间序列特征,实现16QAM、32QAM、64QAM、128QAM的准确检测。仿真结果显示,GRU在低SNR下表现优异,且训练速度快,参数少。核心程序包括模型预测、误检率和漏检率计算,并绘制准确率图。
204 65
基于GRU网络的MQAM调制信号检测算法matlab仿真,对比LSTM
|
4月前
|
机器学习/深度学习 监控 算法
面向办公室屏幕监控系统的改进型四叉树屏幕变化检测算法研究
本文提出一种改进型四叉树数据结构模型,用于优化办公室屏幕监控系统。通过动态阈值调节、变化优先级索引及增量更新策略,显著降低计算复杂度并提升实时响应能力。实验表明,该算法在典型企业环境中将屏幕变化检测效率提升40%以上,同时减少资源消耗。其应用场景涵盖安全审计、工作效能分析及远程协作优化等,未来可结合深度学习实现更智能化的功能。
82 0
|
12月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于MSER和HOG特征提取的SVM交通标志检测和识别算法matlab仿真
### 算法简介 1. **算法运行效果图预览**:展示算法效果,完整程序运行后无水印。 2. **算法运行软件版本**:Matlab 2017b。 3. **部分核心程序**:完整版代码包含中文注释及操作步骤视频。 4. **算法理论概述**: - **MSER**:用于检测显著区域,提取图像中稳定区域,适用于光照变化下的交通标志检测。 - **HOG特征提取**:通过计算图像小区域的梯度直方图捕捉局部纹理信息,用于物体检测。 - **SVM**:寻找最大化间隔的超平面以分类样本。 整个算法流程图见下图。
|
7月前
|
机器学习/深度学习 存储 算法
基于MobileNet深度学习网络的活体人脸识别检测算法matlab仿真
本内容主要介绍一种基于MobileNet深度学习网络的活体人脸识别检测技术及MQAM调制类型识别方法。完整程序运行效果无水印,需使用Matlab2022a版本。核心代码包含详细中文注释与操作视频。理论概述中提到,传统人脸识别易受非活体攻击影响,而MobileNet通过轻量化的深度可分离卷积结构,在保证准确性的同时提升检测效率。活体人脸与非活体在纹理和光照上存在显著差异,MobileNet可有效提取人脸高级特征,为无线通信领域提供先进的调制类型识别方案。
|
8月前
|
机器学习/深度学习 算法 安全
基于深度学习的路面裂缝检测算法matlab仿真
本项目基于YOLOv2算法实现高效的路面裂缝检测,使用Matlab 2022a开发。完整程序运行效果无水印,核心代码配有详细中文注释及操作视频。通过深度学习技术,将目标检测转化为回归问题,直接预测裂缝位置和类别,大幅提升检测效率与准确性。适用于实时检测任务,确保道路安全维护。 简介涵盖了算法理论、数据集准备、网络训练及检测过程,采用Darknet-19卷积神经网络结构,结合随机梯度下降算法进行训练。
|
7月前
|
机器学习/深度学习 数据采集 算法
基于yolov2和googlenet网络的疲劳驾驶检测算法matlab仿真
本内容展示了基于深度学习的疲劳驾驶检测算法,包括算法运行效果预览(无水印)、Matlab 2022a 软件版本说明、部分核心程序(完整版含中文注释与操作视频)。理论部分详细阐述了疲劳检测原理,通过对比疲劳与正常状态下的特征差异,结合深度学习模型提取驾驶员面部特征变化。具体流程包括数据收集、预处理、模型训练与评估,使用数学公式描述损失函数和推理过程。课题基于 YOLOv2 和 GoogleNet,先用 YOLOv2 定位驾驶员面部区域,再由 GoogleNet 分析特征判断疲劳状态,提供高准确率与鲁棒性的检测方法。
|
8月前
|
机器学习/深度学习 人工智能 运维
[ICDE2024]多正常模式感知的频域异常检测算法MACE
[ICDE2024]多正常模式感知的频域异常检测算法MACE

热门文章

最新文章