/// <summary> /// Solves the single-source shortest path problem in O(E*ln V) time for a graph with none-negative edge weights. /// </summary> public static Paths <V> Dijkstra <V>(DiGraph <V> graph, V source) where V : class { if (graph == null || source == null) { throw new ArgumentNullException(); } if (!graph.Contains(source)) { throw new ArgumentException(); } if (graph.Edges().Any(e => e.weight < 0)) { throw new ArgumentException(); } var queue = new BinaryHeap <Double, V>(); var distTo = new HashMap <V, Double>(); var edgeTo = new HashMap <V, Edge <V> >(); void Relax(Edge <V> e) { var(v, w) = (e.from, e.to); var weight = new Double(e.weight); if (distTo[v] > distTo[w] + weight) { distTo[w] = distTo[v] + weight; edgeTo[w] = e; if (queue.Contains(w)) { queue.Update(w, distTo[w]); } else { queue.Push(w, distTo[w]); } } } foreach (var v in graph.Vertices()) { distTo[v] = Double.MaxValue; } distTo[source] = new Double(0); queue.Push(source, new Double(0)); while (!queue.IsEmpty()) { var(_, v) = queue.Pop(); foreach (var e in graph.Edges(v)) { Relax(e); } } return(new Paths <V>(source, edgeTo)); }
/// <summary> /// Solves the single-source shortest path problem in O(E*V) time for a graph without any negative cycles, or in O(V+E) time if it is a DAG. /// </summary> public static Paths <V> BellmanFord <V>(DiGraph <V> graph, V source) { if (graph == null || source == null) { throw new ArgumentNullException(); } if (!graph.Contains(source)) { throw new ArgumentException(); } var distTo = new HashMap <V, Double>(); var edgeTo = new HashMap <V, Edge <V> >(); bool Relax(Edge <V> e) { var(v, w) = (e.from, e.to); var weight = new Double(e.weight); if (distTo[v] > distTo[w] + weight) { distTo[w] = distTo[v] + weight; edgeTo[w] = e; return(true); } return(false); } foreach (var v in graph.Vertices()) { distTo[v] = Double.MaxValue; } distTo[source] = new Double(0); // The Bellman Ford procedure involves relaxing every edge V times. // However, for a DAG we can delegate to a simpler algorithm that runs in linear time try { var vertices = TopologicalSort(graph); foreach (var v in vertices) { foreach (var e in graph.Edges(v)) { Relax(e); } } } catch (InvalidOperationException) { // Graph is not a DAG var N = graph.Size(); foreach (var i in Enumerable.Range(1, N)) { foreach (var e in graph.Edges()) { var relaxed = Relax(e); if (i == N && relaxed) { throw new InvalidOperationException("Negative cycle detected"); } } } } return(new Paths <V>(source, edgeTo)); }