深度优先搜索检测有向图有无环路算法

简介:

给定有向图 G = (V, E),需要判断该图中是否存在环路(Cycle)。例如,下面的图 G 中包含 4 个顶点和 6 条边。

实际上,上图中存在 3 个环路:0->2->0, 0->1->2->0, 3->3。

深度优先搜索(DFS:Depth-First Search)可以用于检测图中是否存在环。DFS 会对一个连通的图构造一颗树,如果在构造树的过程中出现反向边(Back Edge),则认为图中存在环路。

对于非连通图,可以对图中的不同部分分别进行 DFS 构造树结构,对于每棵树分别检测反向边的存在。

在 DFS 对图进行遍历时,将遍历过的顶点放入递归栈中,如果新遍历的顶点已经存在于递归栈中,则说明存在一个反向边,即存在一个环。

复制代码
  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(6);
 12       g.AddEdge(0, 1, 16);
 13       g.AddEdge(0, 2, 13);
 14       g.AddEdge(1, 2, 10);
 15       g.AddEdge(1, 3, 12);
 16       g.AddEdge(2, 1, 4);
 17       g.AddEdge(2, 4, 14);
 18       //g.AddEdge(3, 2, 9);
 19       g.AddEdge(3, 5, 20);
 20       //g.AddEdge(4, 3, 7);
 21       //g.AddEdge(4, 5, 4);
 22 
 23       Console.WriteLine();
 24       Console.WriteLine("Graph Vertex Count : {0}", g.VertexCount);
 25       Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount);
 26       Console.WriteLine();
 27 
 28       Console.WriteLine("Is there cycle in graph: {0}", g.HasCycle());
 29 
 30       Console.ReadKey();
 31     }
 32 
 33     class Edge
 34     {
 35       public Edge(int begin, int end, int weight)
 36       {
 37         this.Begin = begin;
 38         this.End = end;
 39         this.Weight = weight;
 40       }
 41 
 42       public int Begin { get; private set; }
 43       public int End { get; private set; }
 44       public int Weight { get; private set; }
 45 
 46       public override string ToString()
 47       {
 48         return string.Format(
 49           "Begin[{0}], End[{1}], Weight[{2}]",
 50           Begin, End, Weight);
 51       }
 52     }
 53 
 54     class Graph
 55     {
 56       private Dictionary<int, List<Edge>> _adjacentEdges
 57         = new Dictionary<int, List<Edge>>();
 58 
 59       public Graph(int vertexCount)
 60       {
 61         this.VertexCount = vertexCount;
 62       }
 63 
 64       public int VertexCount { get; private set; }
 65 
 66       public IEnumerable<int> Vertices { get { return _adjacentEdges.Keys; } }
 67 
 68       public IEnumerable<Edge> Edges
 69       {
 70         get { return _adjacentEdges.Values.SelectMany(e => e); }
 71       }
 72 
 73       public int EdgeCount { get { return this.Edges.Count(); } }
 74 
 75       public void AddEdge(int begin, int end, int weight)
 76       {
 77         if (!_adjacentEdges.ContainsKey(begin))
 78         {
 79           var edges = new List<Edge>();
 80           _adjacentEdges.Add(begin, edges);
 81         }
 82 
 83         _adjacentEdges[begin].Add(new Edge(begin, end, weight));
 84       }
 85 
 86       public bool HasCycle()
 87       {
 88         // mark all the vertices as not visited 
 89         // and not part of recursion stack
 90         bool[] visited = new bool[VertexCount];
 91         bool[] recursionStack = new bool[VertexCount];
 92         for (int i = 0; i < VertexCount; i++)
 93         {
 94           visited[i] = false;
 95           recursionStack[i] = false;
 96         }
 97 
 98         // call the recursive helper function to 
 99         // detect cycle in different DFS trees
100         for (int i = 0; i < VertexCount; i++)
101           if (CheckCyclic(i, visited, recursionStack))
102             return true;
103 
104         return false;
105       }
106 
107       private bool CheckCyclic(int v, bool[] visited, bool[] recursionStack)
108       {
109         if (!visited[v])
110         {
111           // mark the current node as visited 
112           // and part of recursion stack
113           visited[v] = true;
114           recursionStack[v] = true;
115 
116           // recur for all the vertices adjacent to this vertex
117           if (_adjacentEdges.ContainsKey(v))
118           {
119             foreach (var edge in _adjacentEdges[v])
120             {
121               if (!visited[edge.End]
122                 && CheckCyclic(edge.End, visited, recursionStack))
123                 return true;
124               else if (recursionStack[edge.End])
125                 return true;
126             }
127           }
128         }
129 
130         // remove the vertex from recursion stack
131         recursionStack[v] = false;
132 
133         return false;
134       }
135     }
136   }
137 }
复制代码




目录
相关文章
|
3天前
|
算法 安全
分别使用OVP-UVP和OFP-UFP算法以及AFD检测算法实现反孤岛检测simulink建模与仿真
本课题通过Simulink建模与仿真,实现OVP-UVP、OFP-UFP算法及AFD检测算法的反孤岛检测。OVP-UVP基于电压幅值变化,OFP-UFP基于频率变化,而AFD则通过注入频率偏移信号来检测孤岛效应,确保电力系统安全稳定运行。系统使用MATLAB 2013b进行建模与仿真验证。
|
2月前
|
机器学习/深度学习 监控 算法
目标检测算法技术
8月更文挑战第11天
|
2月前
|
机器学习/深度学习 监控 算法
目标检测算法
8月更文挑战第5天
|
2月前
|
机器学习/深度学习 监控 算法
目标检测算法
8月更文挑战第8天
|
3月前
|
监控 算法 自动驾驶
目标检测算法:从理论到实践的深度探索
【7月更文第18天】目标检测,作为计算机视觉领域的核心任务之一,旨在识别图像或视频中特定对象的位置及其类别。这一技术在自动驾驶、视频监控、医疗影像分析等多个领域发挥着至关重要的作用。本文将深入浅出地介绍目标检测的基本概念、主流算法,并通过一个实际的代码示例,带您领略YOLOv5这一高效目标检测模型的魅力。
386 11
|
3月前
|
机器学习/深度学习 人工智能 监控
人工智能 - 目标检测算法详解及实战
目标检测需识别目标类别与位置,核心挑战为复杂背景下的多目标精准快速检测。算法分两步:目标提取(滑动窗口或区域提议)和分类(常用CNN)。IoU衡量预测与真实框重叠度,越接近1,检测越准。主流算法包括R-CNN系列(R-CNN, Fast R-CNN, Faster R-CNN),YOLO系列,SSD,各具特色,如Faster R-CNN高效候选区生成与检测,YOLO适用于实时应用。应用场景丰富,如自动驾驶行人车辆检测,安防监控,智能零售商品识别等。实现涉及数据准备、模型训练(示例YOLOv3)、评估(Precision, Recall, mAP)及测试。
100 5
|
3月前
|
机器学习/深度学习 人工智能 算法
计算机视觉:目标检测算法综述
【7月更文挑战第13天】目标检测作为计算机视觉领域的重要研究方向,近年来在深度学习技术的推动下取得了显著进展。然而,面对复杂多变的实际应用场景,仍需不断研究和探索更加高效、鲁棒的目标检测算法。随着技术的不断发展和应用场景的不断拓展,相信目标检测算法将在更多领域发挥重要作用。
|
3天前
|
传感器 算法 C语言
基于无线传感器网络的节点分簇算法matlab仿真
该程序对传感器网络进行分簇,考虑节点能量状态、拓扑位置及孤立节点等因素。相较于LEACH算法,本程序评估网络持续时间、节点死亡趋势及能量消耗。使用MATLAB 2022a版本运行,展示了节点能量管理优化及网络生命周期延长的效果。通过簇头管理和数据融合,实现了能量高效和网络可扩展性。
|
1月前
|
算法 BI Serverless
基于鱼群算法的散热片形状优化matlab仿真
本研究利用浴盆曲线模拟空隙外形,并通过鱼群算法(FSA)优化浴盆曲线参数,以获得最佳孔隙度值及对应的R值。FSA通过模拟鱼群的聚群、避障和觅食行为,实现高效全局搜索。具体步骤包括初始化鱼群、计算适应度值、更新位置及判断终止条件。最终确定散热片的最佳形状参数。仿真结果显示该方法能显著提高优化效率。相关代码使用MATLAB 2022a实现。
|
1月前
|
算法 数据可视化
基于SSA奇异谱分析算法的时间序列趋势线提取matlab仿真
奇异谱分析(SSA)是一种基于奇异值分解(SVD)和轨迹矩阵的非线性、非参数时间序列分析方法,适用于提取趋势、周期性和噪声成分。本项目使用MATLAB 2022a版本实现从强干扰序列中提取趋势线,并通过可视化展示了原时间序列与提取的趋势分量。代码实现了滑动窗口下的奇异值分解和分组重构,适用于非线性和非平稳时间序列分析。此方法在气候变化、金融市场和生物医学信号处理等领域有广泛应用。
下一篇
无影云桌面