Editing Shortest path

Jump to: navigation, search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision Your text
Line 47: Line 47:
==Single-source shortest paths==
==Single-source shortest paths==
In an unweighted graph, the single-source shortest paths may be determined by performing [[breadth-first search]] from the source. This is correct by definition; breadth-first search visits nodes in increasing order of their distance from the start node, so that as soon as we visit a node, we immediately know the correct distance to this node. This is guaranteed to terminate after considering each edge at most twice (once from each end in an undirected graph), since we do not expand from nodes that have already been visited. It follows that the running time is <math>O(E+V)</math>. BFS also solves the problem when some edges are allowed to have weight zero (by using a [[deque]] in place of the [[queue]]).
In a weighted graph with nonnegative weights, it is still possible to visit the vertices in increasing order of distance from the source. This is because the source is obviously the closest to itself, the next closest vertex is obviously one of its immediate neighbors, the next closest is obviously either another immediate neighbor of the source or an immediate neighbor of the second closest vertex, and so on --- the length of a path cannot decrease as more nodes are added to the end of it. So by replacing the queue with a [[priority queue]] and greedily picking the next vertex to visit, we obtain [[Dijkstra's algorithm]], which is slower by only a log factor due to the priority queue, <math>O((E+V)\log V)</math> overall in a finite graph. (In a dense graph, it is also possible to implement this in <math>O(E+V^2)</math> time, which is asymptotically optimal in this case.)
If, on the other hand, edges of negative weight exist, but not in a way that introduces negative-weight cycles, there is still a simple way to find shortest paths, known as the [[Bellman–Ford algorithm]]. This works by repeatedly trying to relax each edge in the graph; it is not too hard to show that after doing this enough times, the correct shortest paths will all be known. Specifically, <math>V-1</math> iterations are required, so the running time is <math>O(VE)</math>. Another solution, which is sometimes faster, is the [[Shortest Path Faster Algorithm]] (SPFA).
==All-pairs shortest paths==
==All-pairs shortest paths==
We might try to find all-pairs shortest paths by running a single-source shortest paths algorithm using each vertex in turn as the source. Hence, we have the following bounds with a [[binary heap]] implementation of the [[priority queue]] ADT:
* <math>O(V(E+V))</math> when the graph is unweighted
* <math>O(V(E+V)\log V)</math> when the edge weights are nonnegative and the graph is sparse (<math>O(V(E + \log V))</math> using a [[Fibonacci heap]])
* <math>O(VE+V^3)</math> when the edge weights are nonnegative and the graph is dense
* <math>O(V^2E)</math> when edge weights are allowed to be negative, but no negative-weight cycles exist.
There is also a general-purpose technique called the [[Floyd–Warshall]] algorithm, which is often considered [[Dynamic programming|dynamic]], that solves all four cases in <math>O(V^3)</math> time. It works by using each vertex in turn and using it to try to relax the distance between every pair of nodes in the graph. When the graph is dense, Floyd–Warshall is just as fast as BFS or Dijkstra's, and it always outperforms Bellman–Ford. So we have the bound <math>O(V(E+V)\log V)</math> for sparse graphs with nonnegative edge weights and <math>O(V^3)</math> for dense graphs.
What if the graph is sparse and it has negative edge weights? Can we do better than <math>O(V^3)</math> here? Not using the Bellman–Ford algorithm <math>V</math> times, certainly. However, it turns out that it is possible to run Bellman–Ford ''once'' and thus transform the graph into a form in which all edge weights are nonnegative, then run Dijkstra's <math>V</math> times. This gives a method known as [[Johnson's algorithm]] that matches the time bound for graphs with nonnegative edge weights (since the time taken to run Bellman–Ford is asymptotically dominated by the time taken to run <math>V</math> invocations of Dijkstra's).
==Single-pair shortest path==
==Single-pair shortest path==
We can compute a single-pair shortest path by taking the source <math>s</math> and running single-source shortest paths from it, and simply extracting the shortest path to the destination <math>t</math>. This computes a lot of extra information (namely, the shortest paths to all the other vertices as well), so we might wonder whether it is possible to do better. It turns out that there are no known single-pair shortest path algorithms that outperform single-source shortest paths algorithms ''in the worst case''. Nevertheless, it is often possible to do better in the ''average case''.
(Note: if edges of negative weight are allowed to exist in an infinite graph, then the problem is impossible; if any bound on the running time to find a shortest path is claimed, we can defeat this claim by constructing a graph in which the shortest path involves a highly negatively weighted edge that is extremely far away, too far to be explored within the time bound.)
===A* or heuristic search===
In the single-pair shortest path problem, we know exactly where we want to go, we just don't know how to get there. But what if we were able to guess roughly how far away we are from the destination? Then we could proceed as in Dijkstra's algorithm, but give priority to exploring edges that we think take us closer to the destination rather than further away. Formally, we define a ''heuristic function'' <math>h:V \to \mathbb{R}</math> such that <math>h(v)</math> is a "guess" for the actual distance between <math>v</math> and <math>t</math> (the destination). If we can find such a heuristic function that never ''overestimates'' (only underestimates) the correct distance, we can use the [[A* search algorithm]] to take advantage of this information to help find a shortest path more quickly. (If <math>h</math> overestimates, then we may still get a relatively short path, but we are not guaranteed that it is a correct shortest path.) The better our estimates with <math>h</math>, the faster the search, but in the worst case, in which our heuristic is totally off, we cannot improve much over Dijkstra's.
Another example of when we don't have to worry much about the worst case, and hence might be able to get a better search time, is when the graph we are searching is extremely large but yet we know that the shortest path is relatively short. For example, consider the Rubik's cube graph, in which each legal position is a vertex and an edge exists between two vertices if the positions they represent can be interconverted with one face turn. There are approximately <math>4.3\times10^{19}</math> positions of the Rubik's cube, but the shortest path between any pair of vertices always has length 20 or less.<ref>Tomas Rokicki ''et al.'' "God's Number is 20". Retrieved 2011-03-02 from http://cube20.org/</ref> The graph we are searching may even be infinite.
Meet-in-the-middle search works similarly to a single-source search such as BFS or Djikstra's algorithm, but it differs in that the algorithm branches outward from both the source and the destination (''backward'' along directed edges, if any). In this way we simultaneously build the beginning of the path (by searching from the source) and the end (by searching from the destination). When a common vertex is reached, these two pieces of the path may be assembled to form the full path. To understand why this is faster, imagine we were to execute BFS on the Rubik's Cube graph in order to try to find a path from a scrambled position to the solved position. Each vertex in the graph has degree 18 (three possible moves per face), so, if the distance from the scrambled position to the solved position is, say, 8, we will visit on the order of 18<sup>8</sup> vertices in the search (about 11 billion). If on the other hand we found this path by finding a path of length 4 from the source and a path of length 4 from the destination that happened to share an endpoint, we would only visit on the order of 2&times;18<sup>4</sup> vertices, which is about 210000. So we have cut down the size of the part of the graph we have to explore by a factor of about 50000. Note however that there is no free lunch; we need some way of determining when a vertex has been visited both forward and backward, such as a hash table.

Please note that all contributions to PEGWiki are considered to be released under the Attribution 3.0 Unported (see PEGWiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

Cancel | Editing help (opens in new window)