/// <summary> /// Tries to compute the shortest paths in a weighted graph with the Bellman-Ford's algorithm. Returns true if successful; otherwise false. /// </summary> /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam> /// <typeparam name="TWeight">The data type of weight of the edges. TWeight implements <see cref="IComparable{T}"/>.</typeparam> /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/>.</param> /// <param name="source">The source vertex for which the shortest paths are computed.</param> /// <param name="shortestPaths">The <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object that contains the shortest paths of the graph if the algorithm was successful; otherwise null.</param> /// <param name="weightAdder">The method corresponding to the <see cref="AddWeights{TWeight}"/> delegate used for calculating the sum of two edge weights.</param> /// <returns>Returns true if the shortest paths were successfully computed; otherwise false. Also returns false if the given source vertex does not belong to the graph.</returns> public static bool TryGetBellmanFordShortestPaths <TVertex, TWeight>(this IWeightedGraph <TVertex, TWeight> graph, TVertex source, out WeightedGraphShortestPaths <TVertex, TWeight> shortestPaths, AddWeights <TWeight> weightAdder) where TVertex : IComparable <TVertex> where TWeight : IComparable <TWeight> { shortestPaths = null; if (!graph.ContainsVertex(source)) { return(false); } // A dictionary holding a vertex as key and as value a key-value pair of its previous vertex in the path(being the key) and the weight of the edge connecting them(being the value). var previousVertices = new Dictionary <TVertex, KeyValuePair <TVertex, TWeight> >(); // The dictionary holding a vertex as key and as value a key-value pair holding the weight of the path from the source vertex(being the key) and the distance from the source vertex(being the value). var weightAndDistance = new Dictionary <TVertex, KeyValuePair <TWeight, int> >(); // Add source vertex to computed weights and distances weightAndDistance.Add(source, new KeyValuePair <TWeight, int>(default(TWeight), 0)); // Get all edges and sort them by their source and then by their destination vertex to create a consistent shortest paths output. var allEdges = graph.Edges.ToList(); if (allEdges.Count > 0) { allEdges.QuickSort((x, y) => { int cmp = x.Source.CompareTo(y.Source); if (cmp == 0) { cmp = x.Destination.CompareTo(y.Destination); } return(cmp); }); } // We relax all edges n - 1 times and if at the n-th step a relaxation is needed we have a negative cycle int lastStep = graph.VerticesCount - 1; for (int i = 0; i < graph.VerticesCount; i++) { foreach (var edge in allEdges) { var edgeSource = edge.Source; var edgeDestination = edge.Destination; var edgeWeight = edge.Weight; // If we have computed the path to the the source vertex of the edge if (weightAndDistance.ContainsKey(edgeSource)) { var wd = weightAndDistance[edgeSource]; TWeight curWeight = wd.Key; int curDistance = wd.Value; // If the edge destination is the source we continue with the next edge if (object.Equals(source, edgeDestination)) { continue; } // Compute path weight TWeight pathWeight; if (curWeight == null) { pathWeight = edgeWeight; } else { pathWeight = weightAdder(curWeight, edgeWeight); } // If this path is longer than an already computed path we continue with the next edge if (weightAndDistance.ContainsKey(edgeDestination)) { int cmp = pathWeight.CompareTo(weightAndDistance[edgeDestination].Key); if (cmp > 0) { continue; } else if (cmp == 0)// if path is equal to an already computed path { // we continue with the next edge only if the distance is bigger or equal if (curDistance + 1 >= weightAndDistance[edgeDestination].Value) { continue; } // if the distance is smaller we update the path with this one } } if (i == lastStep)// if we need to relax on the last iteration we have a negative cycle { return(false); } // Else we save the path previousVertices[edgeDestination] = new KeyValuePair <TVertex, TWeight>(edgeSource, edgeWeight); weightAndDistance[edgeDestination] = new KeyValuePair <TWeight, int>(pathWeight, curDistance + 1); } } } // Remove source vertex from weight and distance dictionary weightAndDistance.Remove(source); shortestPaths = new WeightedGraphShortestPaths <TVertex, TWeight>(source, previousVertices, weightAndDistance); return(true); }
/// <summary> /// Tries to compute the shortest paths in a weighted graph with the Bellman-Ford's algorithm. Returns true if successful; otherwise false. /// </summary> /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam> /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/> with TWeight being of type <see cref="short"/>.</param> /// <param name="source">The source vertex for which the shortest paths are computed.</param> /// <param name="shortestPaths">The <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object (TWeight being the type of <see cref="short"/>) that contains the shortest paths of the graph if the algorithm was successful; otherwise null.</param> /// <returns>Returns true if the shortest paths were successfully computed; otherwise false. Also returns false if the given source vertex does not belong to the graph.</returns> public static bool TryGetBellmanFordShortestPaths <TVertex>(this IWeightedGraph <TVertex, short> graph, TVertex source, out WeightedGraphShortestPaths <TVertex, short> shortestPaths) where TVertex : IComparable <TVertex> { return(TryGetBellmanFordShortestPaths(graph, source, out shortestPaths, (x, y) => (short)(x + y))); }
/// <summary> /// Uses Dijkstra's algorithm to compute the shortest paths in a weighted graph. Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object containing the shortest paths. /// </summary> /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam> /// <typeparam name="TWeight">The data type of weight of the edges. TWeight implements <see cref="IComparable{T}"/>.</typeparam> /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/>.</param> /// <param name="source">The source vertex for which the shortest paths are computed.</param> /// <param name="weightAdder">The method corresponding to the <see cref="AddWeights{TWeight}"/> delegate used for calculating the sum of two edge weights.</param> /// <returns>Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> containing the shortest paths for the given source vertex.</returns> public static WeightedGraphShortestPaths <TVertex, TWeight> DijkstraShortestPaths <TVertex, TWeight>(this IWeightedGraph <TVertex, TWeight> graph, TVertex source, AddWeights <TWeight> weightAdder) where TVertex : IComparable <TVertex> where TWeight : IComparable <TWeight> { if (!graph.ContainsVertex(source)) { throw new ArgumentException("Vertex does not belong to the graph!"); } // A dictionary holding a vertex as key and as value a key-value pair of its previous vertex in the path(being the key) and the weight of the edge connecting them(being the value). var previousVertices = new Dictionary <TVertex, KeyValuePair <TVertex, TWeight> >(); // The dictionary holding a vertex as key and as value a key-value pair holding the weight of the path from the source vertex(being the key) and the distance from the source vertex(being the value). var weightAndDistance = new Dictionary <TVertex, KeyValuePair <TWeight, int> >(); // Comparer for the key-value pair in the sorted set var kvpComparer = Comparer <KeyValuePair <TWeight, KeyValuePair <TVertex, int> > > .Create((x, y) => { int cmp = 0; // null checking because TWeight can be null if (x.Key == null) { if (y.Key == null) { cmp = -1; // change cmp to skip next comparisons } else { return(int.MinValue); } } if (cmp == 0)// if x.Key and y.Key are not null { if (y.Key == null) { return(int.MaxValue); } // normal check if both weights are not null cmp = x.Key.CompareTo(y.Key); } else { cmp = 0; // if x.Key and y.Key were both null, compare the kvp value } if (cmp == 0) { cmp = x.Value.Key.CompareTo(y.Value.Key); } if (cmp == 0) { cmp = x.Value.Value.CompareTo(y.Value.Value); } return(cmp); }); // Sorted set containing the vertices for computing. Having a kvp with the path weight as key and as value another kvp with the vertex as key and the distance from the source as value. var priorityQueue = new MinPriorityQueue <TWeight, KeyValuePair <TVertex, int> >(kvpComparer); // Add the source vertex priorityQueue.Enqueue(default(TWeight), new KeyValuePair <TVertex, int>(source, 0)); while (priorityQueue.Count > 0) { var curKVP = priorityQueue.Dequeue(); TWeight curWeight = curKVP.Key; TVertex curVertex = curKVP.Value.Key; int curDistance = curKVP.Value.Value; foreach (var edge in graph.OutgoingEdgesSorted(curVertex)) { var edgeDestination = edge.Destination; var edgeWeight = edge.Weight; // If the edge destination is the source we continue with the next edge if (object.Equals(source, edgeDestination)) { continue; } // Compute path weight TWeight pathWeight; if (curWeight == null) { pathWeight = edgeWeight; } else { pathWeight = weightAdder(curWeight, edgeWeight); } // If this path is longer than an already computed path we continue with the next edge if (weightAndDistance.ContainsKey(edgeDestination)) { int cmp = pathWeight.CompareTo(weightAndDistance[edgeDestination].Key); if (cmp > 0) { continue; } else if (cmp == 0)// if path is equal to an already computed path { // we continue with the next edge only if the distance is bigger or equal if (curDistance + 1 >= weightAndDistance[edgeDestination].Value) { continue; } // if the distance is smaller we update the path with this one } } // Else we save the path previousVertices[edgeDestination] = new KeyValuePair <TVertex, TWeight>(curVertex, edgeWeight); weightAndDistance[edgeDestination] = new KeyValuePair <TWeight, int>(pathWeight, curDistance + 1); // Add the destination vertex for computing priorityQueue.Enqueue(pathWeight, new KeyValuePair <TVertex, int>(edgeDestination, curDistance + 1)); } } var shortestPaths = new WeightedGraphShortestPaths <TVertex, TWeight>(source, previousVertices, weightAndDistance); return(shortestPaths); }