Editing Dijkstra's algorithm
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 1: | Line 1: | ||
− | '''Dijkstra's algorithm''' finds [[ | + | '''Dijkstra's algorithm''' finds [[Shortest path|single-source shortest paths]] in a directed graph with non-negative edge weights. (When negative-weight edges are allowed, the [[Bellman–Ford algorithm]] must be used instead.) It is the algorithm of choice for solving this problem, because it is easy to understand, relatively easy to code, and, so far, the fastest algorithm known for solving this problem in the general case. In sparse graphs, running it once on every vertex to generate all-pairs shortest paths is faster than solving the same problem with the [[Floyd–Warshall algorithm]]. (The precise time complexity of Dijkstra's depends on the nature of the data structures used; read on.) |
− | + | =Theory of the algorithm= | |
− | Dijkstra's may be characterized as a [[greedy algorithm]], which builds the shortest-paths tree one edge at a time, adding vertices in non-decreasing order of their distance from the source. That is, in each step of the algorithm, we will find the next-closest vertex to the source. (If there is a tie, it does not matter which one is chosen.) We assume below that all nodes are reachable from the source. | + | Dijkstra's may be characterized as a [[greedy algorithm]], which builds the shortest-paths tree one edge at a time, adding vertices in non-decreasing order of their distance from the source. That is, in each step of the algorithm, we will find the next-closest vertex to the source. (If there is a tie, it does not matter which one is chosen.) We assume below that all nodes are reachable from the source. |
− | + | ==Lemma== | |
− | Suppose that we are given a set <math>T</math> of vertices, containing the source <i>s</i>. We shall call a path <i>admissible</i> if it starts at <i>s</i>, proceeds through a sequence of vertices contained within <math>T</math>, and ends with a single non-<math>T</math> vertex. We claim that there exists an admissible path such that no other path from <i>s</i> to a non-<math>T</math> vertex is shorter. | + | <p>Suppose that we are given a set <math>T</math> of vertices, containing the source <i>s</i>. We shall call a path <i>admissible</i> if it starts at <i>s</i>, proceeds through a sequence of vertices contained within <math>T</math>, and ends with a single non-<math>T</math> vertex. We claim that there exists an admissible path such that no other path from <i>s</i> to a non-<math>T</math> vertex is shorter.</p> |
− | ''Proof'': This consists of nothing but a series of observations. First, any path from <i>s</i> to a vertex <i>v</i> outside <math>T</math> contains at least one edge from a vertex in <math>T</math> to one outside, since <i>s</i> ∈ <math>T</math>. Second, if the first such edge encountered along the path from <i>s</i> is not the last edge in the path, we can "cut off" the path at that point to obtain a path from <i>s</i> out of <math>T</math> that is not longer (since all edges have non-negative weights). Third, if the sub-path from <i>s</i> to the last vertex in <math>T</math>, denoted <i>u</i>, is not itself a shortest path from <i>s</i> to <i>u</i>, the length of the whole path may be decreased by substituting a shortest path from <i>s</i> to <i>u</i> for the current one. Now, suppose the opposite of what we want to prove: the shortest path from <i>s</i> out of <math>T</math>, or all the shortest paths from <i>s</i> out of <math>T</math>, is/are inadmissible. Then we may construct an admissible path using the three observations above which is not longer, a contradiction. | + | <p>''Proof'': This consists of nothing but a series of observations. First, any path from <i>s</i> to a vertex <i>v</i> outside <math>T</math> contains at least one edge from a vertex in <math>T</math> to one outside, since <i>s</i> ∈ <math>T</math>. Second, if the first such edge encountered along the path from <i>s</i> is not the last edge in the path, we can "cut off" the path at that point to obtain a path from <i>s</i> out of <math>T</math> that is not longer (since all edges have non-negative weights). Third, if the sub-path from <i>s</i> to the last vertex in <math>T</math>, denoted <i>u</i>, is not itself a shortest path from <i>s</i> to <i>u</i>, the length of the whole path may be decreased by substituting a shortest path from <i>s</i> to <i>u</i> for the current one. Now, suppose the opposite of what we want to prove: the shortest path from <i>s</i> out of <math>T</math>, or all the shortest paths from <i>s</i> out of <math>T</math>, is/are inadmissible. Then we may construct an admissible path using the three observations above which is not longer, a contradiction.</p> |
− | + | ==The algorithm== | |
− | The preceding Lemma should give us an idea of how to proceed. We start with only the source vertex in the shortest-paths tree | + | The preceding Lemma should give us an idea of how to proceed. We start with only the source vertex in the shortest-paths tree; its distance to itself is obviously zero. Then, we repeatedly apply the Lemma: we consider all outgoing edges <i>u</i>-<i>v</i> of vertices in <math>T</math>; each one induces a possible shortest path from the source <i>s</i> to <i>v</i> when the <i>u</i>-<i>v</i> edge is appended to the shortest <i>s</i>-<i>u</i> path (already known). |
− | + | <!-- <p>To this end, we start with just the source vertex in the tree. Evidently, the distance to it is zero. Now, consider all immediate out-neighbors of the source vertex. If any other vertex is reachable from the source, then the path from the source to it must go through one of the immediate neighbors, and since all weights are non-negative, this path cannot possibly be shorter than that to the immediate neighbor through which it passes. So | |
− | + | ||
<pre> | <pre> | ||
− | input G, | + | input G,v |
− | for each | + | for each u ∈ V(G) |
− | let dist[ | + | let dist[u] = ∞ |
− | let dist[ | + | let dist[v] = 0 |
− | + | for each i ∈ [1..V-1] | |
− | + | for each (u,w) ∈ E(G) | |
− | + | dist[w] = min(dist[w],dist[u]+wt(u,w)) | |
− | + | for each (u,w) ∈ E(G) | |
− | for each | + | if dist[w] > dist[u]+wt(u,w) |
− | dist[w] = min(dist[w],dist[ | + | error "Graph contains negative-weight cycles" |
</pre> | </pre> | ||
− | + | <i>G</i> is the directed, weighted graph in question, and <i>v</i> the source. The output is the array <i>dist</i>; at the completion of the algorithm, <i>dist[x]</i> contains the shortest-path distance from <i>v</i> to <i>x</i>. If the graph contains a cycle of negative weight, an error message is generated to that effect. | |
− | === | + | =Theory of the algorithm= |
− | + | ==How the algorithm works== | |
+ | The algorithm works by performing a series of <i>relaxations</i>. A relaxation occurs whenever the current shortest distance from node <i>v</i> to node <i>w</i> is improved because, by travelling from <i>v</i> to some intermediate vertex <i>u</i>, and then from <i>u</i> to <i>w</i>, a shorter path is obtained. (Floyd–Warshall and Dijkstra's algorithms rely upon this same technique.) The key is that, after <i>N</i> passes of the main loop in Bellman–Ford have completed, at least <i>N</i>+1 of the shortest-path distances in <i>dist</i> are correct. (We consider all pairs of vertices to be connected, so that all "missing" edges are assigned a weight of positive infinity.) | ||
+ | ==Proof of correctness for graphs containing no negative-weight cycles== | ||
+ | We proceed by induction: | ||
+ | * When <math>N=0</math>, there is at least 1 correct entry in <i>dist</i>, the one stating that the distance from the source to itself is zero. | ||
+ | * Now suppose that <math>N</math> passes have occurred and that we know the shortest-path distances from the source to <math>N+1</math> of the vertices. Now, either <math>N</math> is equal to <math>V-1</math>, and we are done, or the vertices may be partitioned into two sets: <math>S</math>, which contains <math>N+1</math> vertices for which we already know shortest-path distances (with any <math>N+1</math> being chosen if there are more than this number), and <math>\overline{S}</math>, which contains the rest. Now, since a shortest-paths tree exists (it always does when there are no negative-weight cycles; the proof is in the [[Shortest path]] article), there must exist some vertex <i>w</i> in <math>\overline{S}</math> whose parent <i>u</i> in the shortest-paths tree is in <math>S</math>. Then, when the edge <i>(u,w)</i> is relaxed, the <i>dist</i> array will contain the correct shortest-path distance to <i>w</i>. Thus, after the next pass of the outer loop has occurred, <math>N+1</math> passes will have occurred in total, and the shortest-path distances to at least <math>(N+1)+1</math> vertices will be correctly known. | ||
+ | Thus, when a negative-weight cycle does not exist, after the main loop has finished, all distances in <i>dist</i> are correct. Now, if an edge <i>(u,w)</i> still exists such that <code>dist[w] > dist[u]+wt(u,w)</code>, then the distances could not possibly have been correct, because relaxation of <i>(u,w)</i> would give a shorter path to <i>w</i>. Since this is a contradiction, the assumption of the non-existence of negative-weight cycles must be incorrect in this case. We see then that as long as there are no negative-weight cycles, the algorithm always computes all distances correctly and terminates successfully. | ||
− | == | + | ==Proof of detection of negative-weight cycles== |
− | + | Suppose vertices <math>v_0, v_1,..., v_{n-1}</math> vertices form a negative-weight cycle, that at some point their entries in the <i>dist</i> array are <math>d_0, d_1,\ldots, d_{n-1}</math>, and that the numbers <math>w_0, w_1,\ldots, w_{n-1}</math> represent the weights of edges in the cycle, where <math>w_i</math> is the weight of the edge from <math>v_i</math> to <math>v_{i+1}</math>. Now, because the cycle has negative weight, we know that <math>w_0+w_1+\ldots+w_{n-1}<0</math>. We show by contradiction that it is always possible to relax one of the edges.<br/> | |
− | + | <br/> | |
− | + | Suppose we assume the opposite: that there exists no <math>i</math> such that <math>d_i + w_i < d_{i+1}</math>. Then, we have <math>d_0 + w_0 \ge d_1, d_1 + w_1 \ge d_2,\ldots, d_{n-1} + w_{n-1} \ge d_0</math>. Adding yields <math>(d_0 + d_1 + \ldots + d_{n-1}) + (w_0 + w_1 + \ldots + w_{n-1}) \ge (d_0 + d_1 + \ldots + d_{n-1})</math>, which, after cancelling the <math>d</math>'s, is a contradiction. So our assumption must be false, and it must always be possible to relax at least one of the edges in a negative-weight cycle. Thus, if there is a negative-weight cycle, it will always be detected at the end of the algorithm, because at least one edge on that cycle must be capable of relaxation. | |
− | + | --> | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | </ | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | < | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | </ | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + |