Why Do |V|-1 Iterations In The Bellman Ford Algorithm Guarantee a Shortest Path? - algorithm

Let V be the set of vertices in a graph. I understand that given a graph of |V| vertices with no negative cycles, a shortest path will always have |V|-1 edges. I still don't quite understand why checking every edge |V|-1 times guarantees that Bellman Ford's algorithm will produce the shortest path. Can someone help me understand this better?

In the first phase (checking every edge once), you consider all potential shortest paths with only one edge. So if the shortest path has only one edge, you will have found it after the first phase. (But you don't yet know that you've found the shortest path.)
After the second phase of checking all edges, you will have considered all potential paths of two edges, since you consider all possible extensions by one edge of the paths you already considered. So if the shortest path has at most two edges, you will have found it after the second phase.
And so on… If the shortest path has at most |V|−1 edges (which it does), you will have found it after |V|−1 phases.

This is done in the relaxation step. In this step, vertice distances are updated incrementally. Intuitively, these updates are propagated throughout the graph: When you find a shorter path to one node, then its neighbours might also benefit from this shortcut. In the next iteration, they get updated too, and so on.
But this updating cannot continue indefinitely. The maximum number of times it can occur is precisely |V| - 1. You can visualise it as a path of updates propagating from one vertex, throughout all other vertices, back to the source. The source itself of course does not find a shortcut to itself.

In my opinion, it's necessary to do some math to understand it fully (although the other answers already give some intuition). Let's prove the following statement by induction:
Let s be the source vertex and u be any other vertex in the directed graph. After i iterations of Bellman-ford algorithm:
if d[u] is not infinity, it is equal to the length of some path from s to u.
if there is a path from s to u with at most i edges, then d[u] is at most the length of the shortest path from s to u with at most i edges.
Proof
The base case is i=0 (before any iteration). At this moment, d[s] = 0 and d[u] = ∞ for all u. It's obvious that (1) and (2) are valid for this case.
Let's consider that it's valid for i (inductive hypothesis).
At the i+1 iteration, consider a moment when a vertex v distance is updated by d[v] := d[u] + w[u][v]. By the inductive hypothesis, d[u] is the length of some path from s to u. Then d[u] + w[u][v] is the length of the path from source to v that follows the path from source to u and then goes to v. So, (1) is valid for the (i+1)-th iteration and by induction is valid for all natural i.
Now, consider a shortest path P (there may be more than one) from s to v with at most i+1 edges. Let u be the last vertex before v on this path. Then, the part of the path from s to u is a shortest path from s to u with at most i edges. Indeed, suppose that it's not. Then there would exist some strictly shorter path from s to u with at most i edges, which could be appended to the edge uv to obtain a path with at most i edges that is strictly shorter than P, which is contradiction. By inductive hypothesis, d[u] after i iterations is at most the length of the shortest path from s to u. Therefore, d[u] + w[u][v] is at most the length of P. In the (i+1)-th iteration, d[v] gets compared with d[u] + w[u][v], and is set equal to it if d[u] + w[u][v] is smaller. Therefore, after i+1 iterations, d[v] is at most the length of P, which is a shortest path from s to v that uses at most i+1 edges. So, (2) is valid for the (i+1)-th iteration and by induction is valid for all natural i.
To finish, notice that if the directed graph has |V| vertices and no negative cycles, a shortest path from a source s to a vertex u has at most |V| - 1 edges. So, by the previous result, Bellman-Ford indeed find all shortest paths from s.

Notice that The Bellman-Ford Algorithm is based on a recursive relationship, which states that:
d(i,v) is the shortest distance from the source to each node v with at most i edges between them.
As i grows to i+1, you allow one more edge, and you update the path length only if it improves.
Since we know that the shortest path can have at most n-1 edges, there is no point to grow i further, i.e, the shortest path has to be:
d(n-1,v).

Related

Why can Dijkstra's Algorithm be modified to find K shortest paths?

I am trying to find an intuitive explanation as to why we can generalize Dijkstra's Algorithm to find the K shortest (simple) paths from a single source in a directed, weighted graph with no negative edges. According to Wikipedia, the pseudocode for the modified Dijkstra is as follows:
Definitions:
G(V, E): weighted directed graph, with set of vertices V and set of directed edges E,
w(u, v): cost of directed edge from node u to node v (costs are non-negative).
Links that do not satisfy constraints on the shortest path are removed from the graph
s: the source node
t: the destination node
K: the number of shortest paths to find
P[u]: a path from s to u
B: a heap data structure containing paths
P: set of shortest paths from s to t
count[u]: number of shortest paths found to node u
Algorithm:
P = empty
for all u in V:
count[u] = 0
insert path P[s] = {s} into B with cost 0
while B is not empty:
let P[u] be the shortest cost path in B with cost C
remove P[u] from B
count[u] = count[u] + 1
if count[u] <= K then:
for each vertex v adjacent to u:
let P[v] be a new path with cost C + w(u, v) formed by concatenating edge (u, v) to path P[u]
insert P[v] into B
return P
I know that, for the original Dijkstra's Algorithm, one can prove by induction that when a node is added to the closed set (or popped from a heap if it's implemented in the form of BFS + heap), the cost to that node must be minimum from the source.
This algorithm here seems to be based on the fact that when a node is popped for the ith time from the heap, we have the ith smallest cost to it from the source. Why is this true?
The Wiki article doesn't specify, but that code will only solve the 'loopy' version of k-shortest-paths, where paths are not required to be simple.
The simple path version of the problem is harder: you'll want to look at something like Yen's algorithm, which does clever filtering to avoid repeated points when generating paths. Yen's algorithm can use Dijkstra's algorithm as a subroutine, but any other shortest-path algorithm can also be used instead.
There is no obvious way to modify Dijkstra's algorithm to solve the k-shortest-simple-paths problem. You'd need to track the paths in the priority queue (which is already done in your posted code), but there's an exponential upper bound on the number of times each vertex can be explored.
Here, if count[u] <= K puts an upper bound of K+1 on the number of times a vertex can be explored, which works for the non-simple path case. On the other hand, a direct modification of Dijkstra's algorithm for simple paths would, in the worst case, require you to explore a node once for each of the 2^(V-1) possibilities of which nodes had been previously visited (or possibly a slightly smaller exponential).

algorithm to solve the replacement paths problem for specific situations

I have to solve this problem and it has been bugging me for hours and I can't seem to find a valid solution that satisfies the time complexity required.
For any edge e in any graph G, let G\e denote the graph obtained by deleting e from G.
(a)Suppose we are given an edge-weighted directed graph G in which the shortest path σ from vertex s to vertex t passes through every vertex of G. Describe an algorithm to compute the shortest-path distance from s to t in G\e, for every edge e of G, in O(VlogV) time. Your algorithm should output a set of E shortest-path distances,one for each edge of the input graph. You may assume that all edge weights are non-negative.[Hint: If we delete an edge of the original shortest path, how do the old and new shortest paths overlap?
(b) Describe an algorithm to solve the replacement paths problem for arbitrary undirected graphs in O(V log V ) time.
a) Consider the shortest path P between vertices s and t. Since P is a shortest path, there is no edge between any two vertices u and v in P in which the length of shortest path between u and v is bigger than 1 in the induced graph P. Since every vertex in G is present in P, So every edge of G is present in the induced graph of P. So we conclude that every edge in G is between two adjacent vertices in P (not the induced graph of P). The only thing you should check for each edge e which connects vertices u and v in G, is that there is another edge which connects u and v in G. If so, the shortest path doesn't change in G/e, otherwise s and t will lie on different components.
First of all I want to mention that the complexity can't only depend on V since the output should contain E values, therefore I guess it should be O(E + Vlog(V)).
I think the following idea should work for problem b) and thus for a) as well. Let σ be the shortest s-t path.
For every edge e in G/E(σ), the shortest path in G/e is still σ.
If we remove an edge e in σ, then the shortest path in the remaining graph would like this: it would start going along σ, then would continue outside (might be from the very first vertex s, then go back to σ (might be at the very last vertex t). Let's then iterate over all edges e=(u,v) that either go from G/σ to σ, or from one vertex of σ, that is closer to s, to another vertex of σ, that is closer to t, as edges of potential candidate paths for some shortest s-t path in G/e' for some e'. Suppose that w is the last vertex in the shortest s-u path U that belongs to σ. Then U+e+σ[v..t] is a potential candidate for a shortest s-t path in graphs G/e' for all e' in σ[w..v]. In order to efficiently store this candidate, we can use a Segment Tree data structure with min operation. This would give us O(E log(E)) total complexity for all updates after we consider all edges. It might be possible to make it O(Vlog(V)) if we look closer at the structure of the updates, but I am not sure at the moment, might be not. Precomputing vertices w for each shortest s-u path above can be done in a single Dijkstra run, if we already have σ.
So in the end the solution runs in O(Elog(E)) time. I am not sure how to make it O(E + Vlog(V)), it is possible to make Dijkstra to run in this time by using Fibonacci heap, but for the updates for candidates I don't really see a faster solution at the moment.

Modifying Dijkstra's Algorithm to find shortest path with largest weighting

I'm in need of a piece of code that finds the shortest path between nodes with the greatest weighting. For example, the quickest route from A to D, but with the greatest weighting:
- B- --E
/ \ /
A D
\ / \
C - -F
So right now the shortest would be ABD or ACD. Once the weighting is applied, the code should choose the longest path out of the two (counter-intuitive, huh?).
I'm trying to modify an algorithm for Dijkstra's Algorithm, but ultimately I just end up traversing the entire graph. Would anyone know how to do this?
Even just an algorithm so I can code it myself would help immensely.
Run BFS from the source (let it be s) on the graph to find the
length of the shortest path from s to the target t, let it be d. Also mark d(s,v) - the distance from s to any node v.
Create a subgraph G'=(V',E') of G such that: v is in V'
only if its distance from the source (s) is at most d - d(s,v) <= d. e=(u,v) is in E' only if: both u and v are in V'.
Create a new graph G*=(V*,E*), where V'=V*, and an edge (u,v) is in E* if it is in E' AND d(s,u) < d(s,v).
Set a new weight function w*(u,v) = -w(u,v), and run Bellman Ford on G* using w*.
The heaviest shortest path in G from s to t is of weight -d(t), and the path found by BF is the matching one.
Time complexity of the algorithm is O(VE), since Bellman-Ford is the bottleneck.
Correctness Proof
Claim 1: The shortest path from s to t does not contain any cycles.
Proof is simple by removing the cycle we get a shorter path.
Claim 2: All shortest paths from s to t are in G'
Proof: Since all shortest paths from s to t are of length d, and we eliminated only nodes with distance from s longer than d, we remove only nodes not needed for shortest paths.
Claim 3: All shortest paths from s to t are in G*.
Proof: Assume we removed some edge (u,v) in a shortest path, and let that path be s->...->x->u->v->y->...->t. Note that the path v->y->..->t is of length d-d(s,u)-1 (assuming d(s,u) is minimal)
However, note that from construction of E*, d(s,v) <= d(s,u) (otherwise (u,v) wouldn't have been removed). So, there is a path s->...->v->y->...->t with distance from s: d(s,v) + d-d(s,u)-1 <= d(s,u) + d - d(s,u) -1 <= d-1 - contradiction to minimality of d.
Claim 4: There are no cycles in G*.
Proof: Assume there is a cycle in G*: v1->v2->vk->v1. By definition of G', all nodes are reachable from s. Without loss of generality, let us assume d(s,v1) is minimal for all other d(s,vi) (otherwise rotate indices to match this assumption). But there is a path v1->v2->...->vk->v1, and d(s,v1)=d(s,v1). This means at least for one edge (vi,vi+1) in this path, d(vi) >= d(vi+1) - which is contradicting the construction of E*, and the cycle does not exist in G*.
Claim 5: The algorithm is correct.
From correctness of Bellman-Ford, and since G* does not contain negative cycles (no cycles at all), BF will find the path with minimal weight according to w* in G*. This path is the one with maximal weight according to w, from the construction of w*.
since all shortest paths in G also exist in G* (and only them), this path is also the shortest path in G with maximal weight.
QED
You can use Dijkstra if you adjust your weights.
If your optimal path must be one that visits the fewest nodes, you can use a high penalty p for traversing each edge and subtract the real weight:
w' = p − w
The penalty must be chosen higher than the highest weight wmax to prevent negative values for w', for which Dijsktra doesn't work. It must also be high enough so that really the shortest path is chosen. A good estimate for p for a graph of n nodes might be:
p &approx; n·wmax
(Edit: My original answer proposed to use reciprocal weights w' = 1/w of each edge instead of the real weight w as an alternative. This will not necessarily give you the shortest path, but one whose weight is high while traversing few edges. This solution does not work for many cases. It is, however, totally independent from the penalty method, which doesn't use reciprocal values.)

Why do all-pair shortest path algorithms work with negative weights?

I've been studying all-pair shortest path algorithms recently such as Floyd-Warshall and Johnson's algorithm, and I've noticed that these algorithms produce correct solutions even when a graph contains negative weight edges (but not negative weight cycles). For comparison, Dijkstra's algorithm (which is single-source shortest path) does not work for negative weight edges. What makes the all-pair shortest path algorithms work with negative weights?
Floyd Warshall's all pairs shortest paths algorithm works for graphs with negative edge weights because the correctness of the algorithm does not depend on edge's weight being non-negative, while the correctness of Dijkstra's algorithm is based on this fact.
Correctness of Dijkstra's algorithm:
We have 2 sets of vertices at any step of the algorithm. Set A consists of the vertices to which we have computed the shortest paths. Set B consists of the remaining vertices.
Inductive Hypothesis: At each step we will assume that all previous iterations are correct.
Inductive Step: When we add a vertex V to the set A and set the distance to be dist[V], we must prove that this distance is optimal. If this is not optimal then there must be some other path to the vertex V that is of shorter length.
Suppose this some other path goes through some vertex X in the set B.
Now, since dist[V] <= dist[X] , therefore any other path to V will be atleast dist[V] length, unless the graph has negative edge lengths.
Correctness of Floyd Warshall's algorithm:
Any path from vertex S to vertex T, will go through any other vertex U of the graph. Thus the shortest path from S to T can be computed as the
min( shortest_path(S to U) + shortest_path(U to T)) for all vertices U in the graph.
As you can see there is no dependence on the graph's edges to be non-negative as long as the sub calls compute the paths correctly. And the sub calls compute the paths correctly as long as the base cases have been properly initialized.
Dijkstra's Algorithm doesn't work for negative weight edge because it is based on the greedy strategy(an assumption) that once a vertex v was added to the set S, d[v] contains the minimum distance possible.
But if the last vertex in Q was added to S and it has some outgoing negative weight edges. The effects on the distance that caused by negative edges won't count.
However, all pairs shortest paths algorithm will capture those updates.

Why doesn't Dijkstra's algorithm work for negative weight edges?

Can somebody tell me why Dijkstra's algorithm for single source shortest path assumes that the edges must be non-negative.
I am talking about only edges not the negative weight cycles.
Recall that in Dijkstra's algorithm, once a vertex is marked as "closed" (and out of the open set) - the algorithm found the shortest path to it, and will never have to develop this node again - it assumes the path developed to this path is the shortest.
But with negative weights - it might not be true. For example:
A
/ \
/ \
/ \
5 2
/ \
B--(-10)-->C
V={A,B,C} ; E = {(A,C,2), (A,B,5), (B,C,-10)}
Dijkstra from A will first develop C, and will later fail to find A->B->C
EDIT a bit deeper explanation:
Note that this is important, because in each relaxation step, the algorithm assumes the "cost" to the "closed" nodes is indeed minimal, and thus the node that will next be selected is also minimal.
The idea of it is: If we have a vertex in open such that its cost is minimal - by adding any positive number to any vertex - the minimality will never change.
Without the constraint on positive numbers - the above assumption is not true.
Since we do "know" each vertex which was "closed" is minimal - we can safely do the relaxation step - without "looking back". If we do need to "look back" - Bellman-Ford offers a recursive-like (DP) solution of doing so.
Consider the graph shown below with the source as Vertex A. First try running Dijkstra’s algorithm yourself on it.
When I refer to Dijkstra’s algorithm in my explanation I will be talking about the Dijkstra's Algorithm as implemented below,
So starting out the values (the distance from the source to the vertex) initially assigned to each vertex are,
We first extract the vertex in Q = [A,B,C] which has smallest value, i.e. A, after which Q = [B, C]. Note A has a directed edge to B and C, also both of them are in Q, therefore we update both of those values,
Now we extract C as (2<5), now Q = [B]. Note that C is connected to nothing, so line16 loop doesn't run.
Finally we extract B, after which . Note B has a directed edge to C but C isn't present in Q therefore we again don't enter the for loop in line16,
So we end up with the distances as
Note how this is wrong as the shortest distance from A to C is 5 + -10 = -5, when you go .
So for this graph Dijkstra's Algorithm wrongly computes the distance from A to C.
This happens because Dijkstra's Algorithm does not try to find a shorter path to vertices which are already extracted from Q.
What the line16 loop is doing is taking the vertex u and saying "hey looks like we can go to v from source via u, is that (alt or alternative) distance any better than the current dist[v] we got? If so lets update dist[v]"
Note that in line16 they check all neighbors v (i.e. a directed edge exists from u to v), of u which are still in Q. In line14 they remove visited notes from Q. So if x is a visited neighbour of u, the path is not even considered as a possible shorter way from source to v.
In our example above, C was a visited neighbour of B, thus the path was not considered, leaving the current shortest path unchanged.
This is actually useful if the edge weights are all positive numbers, because then we wouldn't waste our time considering paths that can't be shorter.
So I say that when running this algorithm if x is extracted from Q before y, then its not possible to find a path - which is shorter. Let me explain this with an example,
As y has just been extracted and x had been extracted before itself, then dist[y] > dist[x] because otherwise y would have been extracted before x. (line 13 min distance first)
And as we already assumed that the edge weights are positive, i.e. length(x,y)>0. So the alternative distance (alt) via y is always sure to be greater, i.e. dist[y] + length(x,y)> dist[x]. So the value of dist[x] would not have been updated even if y was considered as a path to x, thus we conclude that it makes sense to only consider neighbors of y which are still in Q (note comment in line16)
But this thing hinges on our assumption of positive edge length, if length(u,v)<0 then depending on how negative that edge is we might replace the dist[x] after the comparison in line18.
So any dist[x] calculation we make will be incorrect if x is removed before all vertices v - such that x is a neighbour of v with negative edge connecting them - is removed.
Because each of those v vertices is the second last vertex on a potential "better" path from source to x, which is discarded by Dijkstra’s algorithm.
So in the example I gave above, the mistake was because C was removed before B was removed. While that C was a neighbour of B with a negative edge!
Just to clarify, B and C are A's neighbours. B has a single neighbour C and C has no neighbours. length(a,b) is the edge length between the vertices a and b.
Dijkstra's algorithm assumes paths can only become 'heavier', so that if you have a path from A to B with a weight of 3, and a path from A to C with a weight of 3, there's no way you can add an edge and get from A to B through C with a weight of less than 3.
This assumption makes the algorithm faster than algorithms that have to take negative weights into account.
Correctness of Dijkstra's algorithm:
We have 2 sets of vertices at any step of the algorithm. Set A consists of the vertices to which we have computed the shortest paths. Set B consists of the remaining vertices.
Inductive Hypothesis: At each step we will assume that all previous iterations are correct.
Inductive Step: When we add a vertex V to the set A and set the distance to be dist[V], we must prove that this distance is optimal. If this is not optimal then there must be some other path to the vertex V that is of shorter length.
Suppose this some other path goes through some vertex X.
Now, since dist[V] <= dist[X] , therefore any other path to V will be atleast dist[V] length, unless the graph has negative edge lengths.
Thus for dijkstra's algorithm to work, the edge weights must be non negative.
Dijkstra's Algorithm assumes that all edges are positive weighted and this assumption helps the algorithm run faster ( O(E*log(V) ) than others which take into account the possibility of negative edges (e.g bellman ford's algorithm with complexity of O(V^3)).
This algorithm wont give the correct result in the following case (with a -ve edge) where A is the source vertex:
Here, the shortest distance to vertex D from source A should have been 6. But according to Dijkstra's method the shortest distance will be 7 which is incorrect.
Also, Dijkstra's Algorithm may sometimes give correct solution even if there are negative edges. Following is an example of such a case:
However, It will never detect a negative cycle and always produce a result which will always be incorrect if a negative weight cycle is reachable from the source, as in such a case there exists no shortest path in the graph from the source vertex.
Try Dijkstra's algorithm on the following graph, assuming A is the source node and D is the destination, to see what is happening:
Note that you have to follow strictly the algorithm definition and you should not follow your intuition (which tells you the upper path is shorter).
The main insight here is that the algorithm only looks at all directly connected edges and it takes the smallest of these edge. The algorithm does not look ahead. You can modify this behavior , but then it is not the Dijkstra algorithm anymore.
You can use dijkstra's algorithm with negative edges not including negative cycle, but you must allow a vertex can be visited multiple times and that version will lose it's fast time complexity.
In that case practically I've seen it's better to use SPFA algorithm which have normal queue and can handle negative edges.
Recall that in Dijkstra's algorithm, once a vertex is marked as "closed" (and out of the open set) -it assumes that any node originating from it will lead to greater distance so, the algorithm found the shortest path to it, and will never have to develop this node again, but this doesn't hold true in case of negative weights.
The other answers so far demonstrate pretty well why Dijkstra's algorithm cannot handle negative weights on paths.
But the question itself is maybe based on a wrong understanding of the weight of paths. If negative weights on paths would be allowed in pathfinding algorithms in general, then you would get permanent loops that would not stop.
Consider this:
A <- 5 -> B <- (-1) -> C <- 5 -> D
What is the optimal path between A and D?
Any pathfinding algorithm would have to continuously loop between B and C because doing so would reduce the weight of the total path. So allowing negative weights for a connection would render any pathfindig algorithm moot, maybe except if you limit each connection to be used only once.
So, to explain this in more detail, consider the following paths and weights:
Path | Total weight
ABCD | 9
ABCBCD | 7
ABCBCBCD | 5
ABCBCBCBCD | 3
ABCBCBCBCBCD | 1
ABCBCBCBCBCBCD | -1
...
So, what's the perfect path? Any time the algorithm adds a BC step, it reduces the total weight by 2.
So the optimal path is A (BC) D with the BC part being looped forever.
Since Dijkstra's goal is to find the optimal path (not just any path), it, by definition, cannot work with negative weights, since it cannot find the optimal path.
Dijkstra will actually not loop, since it keeps a list of nodes that it has visited. But it will not find a perfect path, but instead just any path.
Adding few points to the explanation, on top of the previous answers, for the following simple example,
Dijktra's algorithm being greedy, it first finds the minimum distance vertex C from the source vertex A greedily and assigns the distance d[C] (from vertex A) to the weight of the edge AC.
The underlying assumption is that since C was picked first, there is no other vertex V in the graph s.t. w(AV) < w(AC), otherwise V would have been picked instead of C, by the algorithm.
Since by above logic, w(AC) <= w(AV), for all vertex V different from the vertices A and C. Now, clearly any other path P that starts from A and ends in C, going through V , i.e., the path P = A -> V -> ... -> C, will be longer in length (>= 2) and total cost of the path P will be sum of the edges on it, i.e., cost(P) >= w(AV) >= w(AC), assuming all edges on P have non-negative weights, so that
C can be safely removed from the queue Q, since d[C] can never get smaller / relaxed further under this assumption.
Obviously, the above assumption does not hold when some.edge on P is negative, in a which case d[C] may decrease further, but the algorithm can't take care of this scenario, since by that time it has removed C from the queue Q.
In Unweighted graph
Dijkstra can even work without set or priority queue, even if you just use STACK the algorithm will work but with Stack its time of execution will increase
Dijkstra don't repeat a node once its processed becoz it always tooks the minimum route , which means if you come to that node via any other path it will certainly have greater distance
For ex -
(0)
/
6 5
/
(2) (1)
\ /
4 7
\ /
(9)
here once you get to node 1 via 0 (as its minimum out of 5 and 6)so now there is no way you can get a minimum value for reaching 1
because all other path will add value to 5 and not decrease it
more over with Negative weights it will fall into infinite loop
In Unweighted graph
Dijkstra Algo will fall into loop if it has negative weight
In Directed graph
Dijkstra Algo will give RIGHT ANSWER except in case of Negative Cycle
Who says Dijkstra never visit a node more than once are 500% wrong
also who says Dijkstra can't work with negative weight are wrong

Resources