/// <summary> /// /// </summary> /// <param name="startvertex"></param> /// <param name="currentvertex"></param> /// <param name="graph"></param> /// <param name="blockedset"></param> /// <param name="blockedmap"></param> /// <param name="stack"></param> /// <param name="allcycles"></param> /// <returns></returns> private bool GetComponentCycles(int startvertex, int currentvertex, IDigraph graph, HashSet <int> blockedset, Dictionary <int, HashSet <int> > blockedmap, Stack <int> stack, List <List <int> > allcycles) { bool hascycle = false; stack.Push(currentvertex); blockedset.Add(currentvertex); if (graph.GetDegreeOut(currentvertex) > 0) { foreach (int neighbor in graph.GetVertexNeighborsOut(currentvertex)) { if (neighbor == startvertex) { List <int> cycle = new List <int>(); stack.Push(startvertex); cycle.AddRange(stack); cycle.Reverse(); stack.Pop(); allcycles.Add(cycle); hascycle = true; } else if (!blockedset.Contains(neighbor)) { bool gotcycle = GetComponentCycles(startvertex, neighbor, graph, blockedset, blockedmap, stack, allcycles); if (gotcycle == true) { hascycle = true; } } } if (hascycle == true) { UnBlock(currentvertex, blockedset, blockedmap); } else { foreach (int neighbor in graph.GetVertexNeighborsOut(currentvertex)) { HashSet <int> bset = GetBlockedSet(neighbor, blockedmap); bset.Add(currentvertex); } } stack.Pop(); return(hascycle); } return(hascycle); }
/// <summary> /// Creates graph consisting of strongly connected components only and then returns the /// minimum vertex among all the strongly connected components graph, ignores single vertex graph since it can't have a cycle /// potentially can return null. /// </summary> /// <param name="sccs"></param> /// <param name="graph"></param> /// <returns></returns> private Nullable <int> LeastIndexSCC(List <HashSet <int> > sccs, IDigraph graph) { int min = int.MaxValue; Nullable <int> minvertex = null; HashSet <int> minscc = null; foreach (HashSet <int> component in sccs) { if (component.Count == 1) { continue; } foreach (int vertex in component) { if (vertex < min) { min = vertex; minvertex = vertex; minscc = component; } } } if (minvertex == null) { return(null); } IDigraph graphscc = new Digraph(graph.VertexCount); for (int i = 0; i < graph.VertexCount; i++) { graphscc.AddVertex(); } for (int i = 0; i < graph.VertexCount; i++) { if (minscc.Contains(i)) { if (graph.GetDegreeOut(i) > 0) { foreach (int neighbor in graph.GetVertexNeighborsOut(i)) { if (minscc.Contains(neighbor)) { graphscc.AddEdge(i, neighbor); } } } } } Nullable <int> potentialminvertex = null; if (graphscc.GetDegreeOut(min) > 0 || graphscc.GetDegreeIn(min) > 0) { potentialminvertex = minvertex; } return(potentialminvertex); }
/// <summary> /// (DIRECTED GRAPH) -Get all strongly connected components of a directed graph. /// Based on Kosaraju's Algorithm: /// https://en.wikipedia.org/wiki/Strongly_connected_component /// https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm /// </summary> /// <param name="graph"></param> /// <returns></returns> public List <HashSet <int> > GetSCC_DirectedGraph(IDigraph graph) { //stack contains vertices by finish time(reverse order) Stack <int> stack = new Stack <int>(); //hashset contains visited vertices HashSet <int> visited = new HashSet <int>(); //List contains all vertices List <int> vertices = new List <int>(); //List of hashsets of vertices representing cycles List <HashSet <int> > connectedcomponents = new List <HashSet <int> >(); //get all connected vertices //add all vertices with edges to unvisited list for (int i = 0; i < graph.VertexCount; i++) { List <int> neighborsout = (List <int>)graph.GetVertexNeighborsOut(i); List <int> neighborsin = (List <int>)graph.GetVertexNeighborsIn(i); if (neighborsout.Count > 0 || neighborsin.Count > 0) { vertices.Add(i); } } foreach (int vertex in vertices) { if (visited.Contains(vertex)) { continue; } DFSUtil(vertex, visited, stack, graph); } //reverse the graph IDigraph reversegraph = ReverseGraph(graph); //empty visited hashset visited.Clear(); while (stack.Count > 0) { //get + remove vertex int at top of the stack int vertex = stack.Pop(); if (visited.Contains(vertex)) { continue; } HashSet <int> componentset = new HashSet <int>(); DFSUtilReverseGraph(vertex, visited, componentset, reversegraph); connectedcomponents.Add(componentset); } return(connectedcomponents); }
/// <summary> /// Depth first search by vertex finish time in decreasing order on the reversed graph /// </summary> /// <param name="vertex"></param> /// <param name="visited"></param> /// <param name="set"></param> /// <param name="reversegraph"></param> private void DFSUtilReverseGraph(int vertex, HashSet <int> visited, HashSet <int> componentset, IDigraph reversegraph) { visited.Add(vertex); componentset.Add(vertex); foreach (int neighbor in reversegraph.GetVertexNeighborsOut(vertex)) { if (visited.Contains(neighbor)) { continue; } DFSUtilReverseGraph(neighbor, visited, componentset, reversegraph); } }
/// <summary> /// Depth first search populates the stack with vertices ordered by finish time (vertex finishing last at top) /// </summary> /// <param name="vertex"></param> /// <param name="visited"></param> /// <param name="stack"></param> /// <param name="graph"></param> private void DFSUtil(int vertex, HashSet <int> visited, Stack <int> stack, IDigraph graph) { visited.Add(vertex); foreach (int neighbor in graph.GetVertexNeighborsOut(vertex)) { if (visited.Contains(neighbor)) { continue; } DFSUtil(neighbor, visited, stack, graph); } stack.Push(vertex); }
/// <summary> /// (DIRECTED GRAPH) -Create a subgraph of an input graph between a start and end vertex (includes start and end vertex) /// </summary> /// <param name="startindex"></param> /// <param name="endvertex"></param> /// <param name="graph"></param> /// <returns></returns> public IDigraph CreateSubGraph(int startindex, int endvertex, IDigraph graph) { IDigraph subgraph = new Digraph(graph.VertexCount); for (int i = 0; i < graph.VertexCount; i++) { subgraph.AddVertex(); } for (int i = startindex; i <= endvertex; i++) { List <int> neighbors = (List <int>)graph.GetVertexNeighborsOut(i); foreach (int neighbor in neighbors) { if (neighbor >= startindex && neighbor <= endvertex) { subgraph.AddEdge(i, neighbor); } } } return(subgraph); }
/// <summary> /// (DIRECTED GRAPH) -Create a copy of the directed graph that is reversed /// </summary> /// <param name="graph"></param> /// <returns></returns> public IDigraph ReverseGraph(IDigraph graph) { IDigraph reversegraph = new Digraph(graph.VertexCount); for (int i = 0; i < graph.VertexCount; i++) { reversegraph.AddVertex(); } for (int i = 0; i < graph.VertexCount; i++) { List <int> vertexneighbors = (List <int>)graph.GetVertexNeighborsOut(i); //for each vertex that is connected, create a reverse edge with its neighbors if (vertexneighbors.Count > 0) { foreach (int neighbor in vertexneighbors) { reversegraph.AddEdge(neighbor, i); } } } return(reversegraph); }