/// <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); }
public DigraphPath(IDigraph g, int s) { _marked = new bool[g.V]; _edgeTo = new int[g.V]; _s = s; dfs(g, s); }
public DigraphPath(IDigraph g, int startVertex) { _marked = new bool[g.V]; _edgeTo = new int[g.V]; _startVertex = startVertex; Dfs(g, startVertex); }
private void dfs(IDigraph graph, int v) { _onStack[v] = true; _marked[v] = true; foreach (int w in graph.Adj(v)) { if (HasCycle) { return; } if (!_marked[w]) { dfs(graph, w); } else if (_onStack[w]) { _cycle = new Stack <int>(); for (int x = v; x != w; x = _edgeTo[x]) { _cycle.Push(x); } _cycle.Push(w); _cycle.Push(v); } } _onStack[v] = false; }
/// <summary> /// (DIRECTED GRAPH) -Get all cycles of a directed graph. /// Based on Johnson's Algorithm: /// https://en.wikipedia.org/wiki/Johnson%27s_algorithm /// https://github.com/mission-peace/interview/blob/master/src/com/interview/graph/AllCyclesInDirectedGraphJohnson.java /// </summary> /// <param name="graph"></param> /// <returns></returns> public List <List <int> > GetAllCycles_DirectedGraph(IDigraph graph) { HashSet <int> blockedset = new HashSet <int>(); Dictionary <int, HashSet <int> > blockedmap = new Dictionary <int, HashSet <int> >(); Stack <int> stack = new Stack <int>(); List <List <int> > allcycles = new List <List <int> >(); int startindex = 0; while (startindex <= graph.VertexCount) { IDigraph subgraph = CreateSubGraph(startindex, graph.VertexCount - 1, graph); List <HashSet <int> > sccs = GetSCC_DirectedGraph(subgraph); Nullable <int> potentialleastvertex = LeastIndexSCC(sccs, subgraph); if (potentialleastvertex != null) { int leastvertex = (int)potentialleastvertex; blockedset.Clear(); blockedmap.Clear(); GetComponentCycles(leastvertex, leastvertex, subgraph, blockedset, blockedmap, stack, allcycles); startindex = leastvertex + 1; } else { break; } } return(allcycles); }
public FindShortestPathInDirectedGraph(IDigraph g, int startVertex) { _marked = new bool[g.V]; _edgeTo = new int[g.V]; _startVertex = startVertex; Bfs(g, startVertex); }
/// <summary> /// Thanks to Morton Mertner for a fix here /// </summary> /// <param name="g"></param> /// <param name="s"></param> /// <returns></returns> public static IDigraph DijkstrasAlgorithm(IDigraph g, int s) { int n = g.NumberOfVertices; Entry[] table = new Entry[n]; for (int v = 0; v < n; ++v) { table[v] = new Entry(false, int.MaxValue, int.MaxValue); } table[s].distance = 0; IPriorityQueue queue = new BinaryHeap(g.NumberOfEdges); queue.Enqueue(new Association(0, g.GetVertex(s))); int vertexCount = 0; // MM fix while (!queue.IsEmpty) { Association assoc = (Association)queue.DequeueMin(); IVertex v0 = (IVertex)assoc.Value; if (!table[v0.Number].known) { table[v0.Number].known = true; vertexCount++; // MM fix foreach (IEdge e in v0.EmanatingEdges) { IVertex v1 = e.MateOf(v0); int d = table[v0.Number].distance + (e.Weight != null ? (int)e.Weight : 0); if (table[v1.Number].distance > d) { table[v1.Number].distance = d; table[v1.Number].predecessor = v0.Number; queue.Enqueue(new Association(d, v1)); } } } } // MM fixed loop to filter out unused edges and vertices IDigraph result = new DigraphAsLists(vertexCount); int cv = 0; int[] v2cv = new int[n]; for (int v = 0; v < n; ++v) { if (table[v].known) { result.AddVertex(cv, table[v].distance); v2cv[v] = cv++; } } for (int v = 0; v < n; ++v) { if (v != s && table[v].known && table[v].distance < int.MaxValue) { result.AddConnection(v2cv[v], v2cv[table[v].predecessor]); } } return(result); }
public TopologicalSort(IDigraph g) { var cycleDirected = new DirectedCycle(g); if (!cycleDirected.HasCycle) { var dfs = new DepthFirstOrder(g); _order = dfs.ReversePost; } }
/// <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); }
public DirectedDFS(IDigraph g, IEnumerable <int> sources) { _marked = new bool[g.V]; foreach (int w in sources) { if (!_marked[w]) { Dfs(g, w); } } }
private void Dfs(IDigraph g, int v) { _marked[v] = true; _count++; foreach (int i in g.Adj(v)) { if (!_marked[i]) { Dfs(g, i); } } }
// edge in reverse postorder (Proposition F. Reverse postorder in a DAG is a topological sort.) public DepthFirstOrder(IDigraph g) { _marked = new bool[g.V]; for (int v = 0; v < g.V; v++) { if (!_marked[v]) { Dfs(g, v); } } }
/// <summary> /// /// </summary> public static TileModel CreateFromGraph(TileMap map, IDigraph graph, int seed = 0) { for (int i = 0; i < graph.VertexCount; i++) { if (graph.GetDegreeOut(i) != map.TileDegree) { throw new ArgumentException($"Vertex {i} is not compatible with the given tile map."); } } return(new TileModel(map, graph.GetVertexNeighborOut, graph.VertexCount, seed)); }
private void dfs(IDigraph graph, int v) { _marked[v] = true; // отмечаем вершину _id[v] = _count; // поставляем номер компонента foreach (int i in graph.Adj(v)) { if (_marked[i]) { continue; } dfs(graph, i); } }
private void Dfs(IDigraph graph, int v) { _marked[v] = true; foreach (int w in graph.Adj(v)) { if (_marked[w]) { continue; } _edgeTo[w] = v; Dfs(graph, w); } }
/// <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> /// 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> /// /// </summary> public static TileModel CreateFromGraph <T>(TileMap <T> tiles, IDigraph graph, int seed = 0) { int degree = tiles.TileDegree; for (int i = 0; i < graph.VertexCount; i++) { if (graph.GetDegreeOut(i) != degree) { throw new ArgumentException($"Vertex {i} is not compatible with the given tile map."); } } return(new TileModel(tiles.CreateConstraints(), graph.GetVertexNeighborOut, graph.VertexCount, tiles.TileCount, seed)); }
private void Dfs(IDigraph g, int v) { _pre.Enqueue(v); _marked[v] = true; for (int w = 0; w < g.V; w++) { if (!_marked[v]) { Dfs(g, w); } } _post.Enqueue(v); _reversePost.Push(v); }
public KosarajuDigraphStronglyConnectedComponents(IDigraph g) { _marked = new bool[g.V]; _id = new int[g.V]; var dfo = new DepthFirstOrder(g.Reverse()); foreach (int w in dfo.ReversePost) { if (!_marked[w]) { dfs(g, w); //помечаем все вершины, которые достижимы из данной _count++; // увеличиваем номер компонента } } }
public DirectedCycle(IDigraph g) { _onStack = new bool[g.V]; _marked = new bool[g.V]; _edgeTo = new int[g.V]; for (int v = 0; v < g.V; v++) { if (_marked[v]) { continue; } dfs(g, v); } }
/// <summary> /// Writes a dot-notation of the given <paramref name="graph"/> to the given <paramref name="writer"/>. /// </summary> /// <param name="graph">The given graph to write out.</param> /// <param name="writer">The writer to write the graph structure to.</param> /// <param name="nodeLabelFunction">A function that generates the labels for the nodes.</param> /// <param name="edgeLabelFunction">A function that generates the labels for the edges.</param> public static void WriteDotStream(this IDigraph graph, TextWriter writer, Func <int, string> nodeLabelFunction, Func <int, int, string> edgeLabelFunction) { writer.Write(KeywordDigraph); writer.WriteLine(KeywordEnvUp); int l = graph.Length; for (int node = 0x00; node < l; node++) { writer.Write(KeywordIdent); writer.Write(NodePrefix); writer.Write(node); string nlabel = nodeLabelFunction(node); if (nlabel != null && nlabel != string.Empty) { writer.Write(KeywordOptUp); writer.Write(KeywordLabel); writer.Write(KeywordKeyVal); writer.Write(KeywordString); writer.Write(nlabel); writer.Write(KeywordString); writer.Write(KeywordOptDn); } writer.WriteLine(KeywordSeparator); } foreach (Tuple <int, int> edge in graph.GetEdges()) { writer.Write(KeywordIdent); writer.Write(NodePrefix); writer.Write(edge.Item1); writer.Write(KeywordDiedge); writer.Write(NodePrefix); writer.Write(edge.Item2); string elabel = edgeLabelFunction(edge.Item1, edge.Item2); if (elabel != null && elabel != string.Empty) { writer.Write(KeywordOptUp); writer.Write(KeywordLabel); writer.Write(KeywordKeyVal); writer.Write(KeywordString); writer.Write(elabel); writer.Write(KeywordString); writer.Write(KeywordOptDn); } writer.WriteLine(KeywordSeparator); } writer.WriteLine(KeywordEnvDn); }
private void Bfs(IDigraph g, int s) { var q = new Queue <int>(); _marked[s] = true; q.Enqueue(s); while (q.Count > 0) { int v = q.Dequeue(); foreach (int w in g.Adj(v)) { if (!_marked[w]) { _edgeTo[w] = v; _marked[w] = true; q.Enqueue(w); } } } }
/// <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> /// Critical path analysis algorithm /// </summary> /// <param name="g"></param> /// <returns></returns> public static IDigraph CriticalPathAnalysis(IDigraph g) { //TODO: more info here int i = g.NumberOfVertices; int[] nums1 = new int[(uint)i]; nums1[0] = 0; g.TopologicalOrderTraversal(new EarliestTimeVisitor(nums1)); int[] nums2 = new int[(uint)i]; nums2[i - 1] = nums1[i - 1]; g.DepthFirstTraversal(new PostOrder(new LatestTimeVisitor(nums2)), 0); IDigraph digraph1 = new DigraphAsLists(i); for (int j = 0; j < i; j++) { digraph1.AddVertex(j); } IEnumerator iEnumerator = g.Edges.GetEnumerator(); try { while (iEnumerator.MoveNext()) { IEdge edge = (IEdge)iEnumerator.Current; int k = nums2[edge.V1.Number] - nums1[edge.V0.Number] - (int)edge.Weight; digraph1.AddConnection(edge.V0.Number, edge.V1.Number, (int)edge.Weight); } } finally { IDisposable iDisposable = iEnumerator as IDisposable; if (iDisposable != null) { iDisposable.Dispose(); } } return(DijkstrasAlgorithm(digraph1, 0)); }
/// <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); }
/// <summary> /// Writes a dot-notation of the given <paramref name="graph"/> to the given <paramref name="writer"/>. /// </summary> /// <param name="graph">The given graph to write out.</param> /// <param name="writer">The writer to write the graph structure to.</param> /// <remarks> /// <para>The <see cref="M:DefaultNodeLabelFunction"/> is used to label the nodes, the method returns the index /// the node prefixed with <c>"n"</c>.</para> /// <para>The <see cref="M:DefaultEdgeLabelFunction"/> is used to label the edges, the method returns the empty /// string for each edge.</para> /// </remarks> public static void WriteDotStream(this IDigraph graph, TextWriter writer) { WriteDotStream(graph, writer, DefaultNodeLabelFunction, DefaultEdgeLabelFunction); }
/// <summary> /// An algorithm for finding the shortest path between two graph vertices /// </summary> /// <param name="g"></param> /// <returns></returns> public static IDigraph FloydsAlgorithm(IDigraph g) { int vertexCount = g.NumberOfVertices; int[,] distance = new int[vertexCount, vertexCount]; for (int j1 = 0; j1 < vertexCount; j1++) { for (int k1 = 0; k1 < vertexCount; k1++) { distance[j1, k1] = int.MaxValue; //means infinity actually } } IEnumerator iEnumerator = g.Edges.GetEnumerator(); try { while (iEnumerator.MoveNext()) { IEdge edge = (IEdge)iEnumerator.Current; distance[edge.V0.Number, edge.V1.Number] = (int)edge.Weight; } } finally { IDisposable iDisposable = iEnumerator as IDisposable; if (iDisposable != null) { iDisposable.Dispose(); } } for (int j2 = 0; j2 < vertexCount; j2++) { for (int k2 = 0; k2 < vertexCount; k2++) { Console.WriteLine(j2 + "->" + k2); for (int i2 = 0; i2 < vertexCount; i2++) { if (distance[j2, i2] != int.MaxValue && distance[i2, k2] != int.MaxValue) { int i3 = distance[j2, i2] + distance[i2, k2]; if (distance[j2, k2] > i3) { distance[j2, k2] = i3; Console.WriteLine(" " + i2); } } } } } IDigraph digraph1 = new DigraphAsMatrix(vertexCount); for (int j3 = 0; j3 < vertexCount; j3++) { digraph1.AddVertex(j3); } for (int k3 = 0; k3 < vertexCount; k3++) { for (int i4 = 0; i4 < vertexCount; i4++) { if (distance[k3, i4] != int.MaxValue) { digraph1.AddConnection(k3, i4, distance[k3, i4]); } } } return(digraph1); }
/// <summary> /// Writes a dot-notation of the given <paramref name="graph"/> to the given <paramref name="writer"/>. /// </summary> /// <param name="graph">The given graph to write out.</param> /// <param name="writer">The writer to write the graph structure to.</param> /// <param name="nodeLabelFunction">A function that generates the labels for the nodes.</param> /// <remarks> /// <para>The <see cref="M:DefaultEdgeLabelFunction"/> is used to label the edges, the method returns the empty /// string for each edge.</para> /// </remarks> public static void WriteDotStream(this IDigraph graph, TextWriter writer, Func <int, string> nodeLabelFunction) { WriteDotStream(graph, writer, nodeLabelFunction, DefaultEdgeLabelFunction); }
public DirectedDFS(IDigraph g, int startVertex) { _marked = new bool[g.V]; Dfs(g, startVertex); }