/// <summary> /// Tries to compute the shortest paths in an unweighted graph with the Bellman-Ford's algorithm. Shortest paths are computed with the distance between the vertices. 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="IGraph{TVertex}"/>.</param> /// <param name="source">The source vertex for which the shortest paths are computed.</param> /// <param name="shortestPaths">The <see cref="UnweightedGraphShortestPaths{TVertex}"/> object 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 IGraph <TVertex> graph, TVertex source, out UnweightedGraphShortestPaths <TVertex> shortestPaths) where TVertex : IComparable <TVertex> { shortestPaths = null; if (!graph.ContainsVertex(source)) { return(false); } // A dictionary holding a vertex as key and its previous vertex in the path as value. var previousVertices = new Dictionary <TVertex, TVertex>(); // A dictionary holding a vertex as key and the distance from the source vertex as value. var pathDistance = new Dictionary <TVertex, int>(); // Add source vertex to computed distances pathDistance.Add(source, 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; // If we have computed the path to the the source vertex of the edge if (pathDistance.ContainsKey(edgeSource)) { int curDistance = pathDistance[edgeSource]; // If the edge destination is the source we continue with the next edge if (object.Equals(source, edgeDestination)) { continue; } int newDistance = curDistance + 1; // If this distance is bigger or equal than an already computed distance we continue with the next edge if (pathDistance.ContainsKey(edgeDestination)) { if (newDistance.CompareTo(pathDistance[edgeDestination]) >= 0) { continue; } } 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] = edgeSource; pathDistance[edgeDestination] = newDistance; } } } // Remove source vertex from path distance dictionary pathDistance.Remove(source); shortestPaths = new UnweightedGraphShortestPaths <TVertex>(source, previousVertices, pathDistance); return(true); }
/// <summary> /// Uses Dijkstra's algorithm to compute the shortest paths in an unweighted graph. Shortest paths are computed with the distance between the vertices. Returns an <see cref="UnweightedGraphShortestPaths{TVertex}"/> object containg the shortest paths. /// </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="IGraph{TVertex}"/>.</param> /// <param name="source">The source vertex for which the shortest paths are computed.</param> /// <returns>Returns a <see cref="UnweightedGraphShortestPaths{TVertex}"/> containing the shortest paths for the given source vertex.</returns> public static UnweightedGraphShortestPaths <TVertex> DijkstraShortestPaths <TVertex>(this IGraph <TVertex> graph, TVertex source) where TVertex : IComparable <TVertex> { if (!graph.ContainsVertex(source)) { throw new ArgumentException("Vertex does not belong to the graph!"); } // A dictionary holding a vertex as key and its previous vertex in the path as value. var previousVertices = new Dictionary <TVertex, TVertex>(); // A dictionary holding a vertex as key and the distance from the source vertex as value. var pathDistance = new Dictionary <TVertex, int>(); // Comparer for the key-value pair in the sorted set var kvpComparer = Comparer <KeyValuePair <int, TVertex> > .Create((x, y) => { var cmp = x.Key.CompareTo(y.Key); if (cmp == 0) { cmp = x.Value.CompareTo(y.Value); } return(cmp); }); // Sorted set containing the vertices for computing. Having a kvp with the distance from the source vertex as a key and the vertex as a value var priorityQueue = new MinPriorityQueue <int, TVertex>(kvpComparer); // Add the source vertex priorityQueue.Enqueue(0, source); while (priorityQueue.Count > 0) { var curKVP = priorityQueue.Dequeue(); TVertex curVertex = curKVP.Value; int curDistance = curKVP.Key; foreach (var edge in graph.OutgoingEdgesSorted(curVertex)) { var edgeDestination = edge.Destination; // If the edge destination is the source we continue with the next edge if (object.Equals(source, edgeDestination)) { continue; } int newDistance = curDistance + 1; // If this distance is bigger or equal than an already computed distance we continue with the next edge if (pathDistance.ContainsKey(edgeDestination)) { if (newDistance.CompareTo(pathDistance[edgeDestination]) >= 0) { continue; } } // Else we save the path previousVertices[edgeDestination] = curVertex; pathDistance[edgeDestination] = newDistance; // Add the destination vertex for computing priorityQueue.Enqueue(newDistance, edgeDestination); } } var shortestPaths = new UnweightedGraphShortestPaths <TVertex>(source, previousVertices, pathDistance); return(shortestPaths); }