給定有向圖 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 }
本篇文章《DFS 檢測有向圖有無環算法》由 Dennis Gao 發表自博客園,未經作者本人同意禁止任何形式的轉載,任何自動或人為的爬蟲轉載行為均為耍流氓。