using System.Collections.Generic; namespace graphs { class DFS where T : notnull { private Graph graph; private int time; private Dictionary Discovered = new Dictionary(); private Dictionary Finished = new Dictionary(); private Dictionary State = new Dictionary(); public DFS(Graph graph) { this.graph = graph; } public DFS Run() { time = 0; foreach (var vertex in graph.Vertices) { if (ColorOf(vertex) == Color.White) { RunFrom(vertex, false); } } return this; } public DFS RunFrom(T start, bool reset = true) { var path = new Stack<(T, IEnumerator)>(); if (reset) { time = 0; } (Discovered[start], State[start]) = (++time, Color.Gray); path.Push((start, graph.GetEdgesFrom(start))); while (path.Count > 0) { var (lastVertex, successors) = path.Peek(); if (!successors.MoveNext()) { path.Pop(); (Finished[lastVertex], State[lastVertex]) = (++time, Color.Black); } else if (ColorOf(successors.Current) == Color.White) { var nextVertex = successors.Current; (Discovered[nextVertex], State[nextVertex]) = (++time, Color.Gray); path.Push((nextVertex, graph.GetEdgesFrom(nextVertex))); } } return this; } private static V GetOrDefault(Dictionary flags, U u, V defaultValue) where U : notnull where V : notnull { if (flags.TryGetValue(u, out var flag)) { return flag; } return defaultValue; } public int DiscoveredAt(T u) => GetOrDefault(Discovered, u, 0); public int FinishedAt(T u) => GetOrDefault(Finished, u, 0); public Color ColorOf(T u) => GetOrDefault(State, u, Color.White); } }