How to set exactly one edge to zero in directed weighted graph in order to find shortest path? - algorithm

The following is the question I am working on:
Consider a directed, weighted graph
G
where all edge weights are
positive. The goal of this problem is to find the shortest path
in
G
between two pre-specified vertices
s
and
t
, but with an added twist: you are allowed to change the weight
of
exactly
one edge (of your
choosing) to zero.
In other words, you must pick an edge in
G
to set to zero that minimizes the shortest
path between
s
and
t
.
Give an efficient algorithm to achieve this goal in
O
(
E
lg
V
) time and analyze your algorithm’s running
time. Sub-optimal solutions will receive less credit.
Hint:
You may have to reverse the edges, run a
familiar algorithm a number of times, plus do some extra work
So I have tried running Dijkstra's from s to all other nodes and then I have tried reversing the edges and running it again from s to all other nodes. However, I found out that we have to run Dijskstra's from s to all other nodes and then reverse the edges and then run Dijkstra's from all other nodes to t. I am not exactly sure how this helps us to find the edge to set to zero. By my intuition I thought that we would simply set the maximum weight edge to zero. What is the point of reversing the edges?

We need to run Dijkstra's algorithm twice - once for the original graph with s as the source vertex, and once with the reversed graph and t as the source vertex. We'll denote the distance we get between vertex s and i from the first run as D(i) and the distance we get between vertex t and i second run D_rev(i).
Note that we can go follow the reversed edges backwards (i.e., follow them in the original direction), thus D_rev(i) is actually the shortest distance from vertex i to t. Similarly, D(i) is the shortest distance from vertex s to i following Dijkstra's algorithm.
We can now loop through all the edges, and for each edge e which connects v1 and v2, add up D(v1) and D_rev(v2), which corresponds to the weight of the path s -> v1 -> v2 -> t with e being the zero edge, since we can go from s to v1 with a distance of D(v1), set e to 0, go from v1 to v2, and then go from v2 to t with a distance of D_rev(v2). The minimum over these is the answer.
A rough proof sketch (and also a restatement) : if we set an edge e to 0, but don't use it in the path, we can be better off setting an edge that's in the path to 0. Thus, we need only consider paths that includes the zeroed edge. The shortest path through a zeroed edge e is to first take the shortest path from s to v1, and then take the shortest path from v2 to t, which are exactly what were computed using the Dijkstra algorithm, i.e., D and D_rev.
Hope this answer helps!

Related

Finding the shortest path with only passing specific edge less or equal to one time in Graph

Given a undirected graph that it has ordinary edges and specific edges, our goal is to find the sum of the shortest path's weight between two vertices(start vertex to end vertex) with only walk through specific edge equal or less than one time. In other words, there are multiple specific edges, and only at most one of them can be used.
This is a problem that I faced in my Data-Structure homework, and I stuck at the first step of the way to storage the weights of the edge in Graph. Because there are two kinds of edge in Graph, I have no idea that how to solve this problem.
I know that I can obtain the shortest path by using Dijkstra’s Algorithm, but during the process, how can I modify the Algorithm to meet the requirement of the restriction?
Thanks a lot for answering my question!
The solution is to duplicate the graph as follows:
Duplicate the vertices, such that for each original vertex A, you have an A and an A'.
If in the original graph there is a normal edge between A and B, then in the new graph, place an edge between A and B and also between A' and B'
If in the original graph there is a specific edge between A and B, then in the new graph place a (directed) edge from A to B' (not the inverse!) and from B to A' (again: not the inverse!). These edges should be directed.
If now the task was to find the shortest path between S and D, then solve in the new graph the problem of finding the shortest path between S and D or S and D', which ever is shortest. You can use a standard implementation of Dijkstra's algorithm for that, starting in S and ending when you find either D or D'.
Given n specific edges run Dijkstra's search n times.
On each run, one of the n nodes (let call it node i) should be set to its real weight and all other n-1 nodes to an infinite value.
At the end of each run store the shortest path and step i
At the end of all runs select from the stored paths the shortest one.
set all n edges weight to infinity
for i=0; i < n ; i++ {
set edge i to it real weight
run run Dijkstra's search
store path
set all n edges weight to infinity
}
select the shortest path from the stored paths.

most lightweight circle in directed graph that goes through specific vertex

I have directed Graph G(V,E) with weight function w. so that weight of each (u,v) is a positive value. I need to find the most lightweight circle in the graph that vertex k' is part of it.
I've also given an algorithm i can use which can find the most lightweight path for a graph with positives weights ( i can use it only once).
I thought about creating a sub graph G' where all vertices and edges that are strongly connected components. find the graph which k' is part of it. then find for the most lightweight adjacent edge from k' to some v of vertices. from that v i can run the algorithm given and find the lightweight path then add the weight of the vertex missing ( (k',v) ).
is that seems correct ? I'm in the beginning of this course and I feel i'm not there yet.
It is a single-source shortest-path problem, where you exclude k->k self-loop as a solution, and find a longer path from k to k. The trick is always expand the shortest path thread.
Given this definition, you can start Googling...
I can't imagine why you called your source vertex k'. Anyway...
Add a new vetrex w that has the same outgoing edges as k'.
Then use Dijkstra's algorithm to find the shortest path from w to k'.
Substitute k' for w in the path, and you have the smallest cycle including k'.
Very interesting problem. I am assuming that there are no negative values in the graph, or otherwise the following solutions requires first normalizing the vertices such that the negative values become at least 0. First method (trivial) is to detect all cycles starting from the target vertex (k). Then compute the weight of all those cycles and take the minimum. The second method is to run Dijkstra algorithm (again watch out negative weights) from the target node (k). Then iterate over all incoming edges of (k), and select the source node that has the minimum Dijkstra value. Now the lightest cycle includes the single path (formed by Dijkstra traversal) from (k) to the chosen node + the bridge to come back to (k). I hope that helps :)

Dijkstra's Single Source Shourtest Path with an extra edge with weight of 'w'

In an recent interview I was asked to implement single source shortest path algorithm(for undirected and positive weighted graph) with slight modification i.e. we're given an extra edge with weight 'w'. And we have to find if we can find a more shorter path, than the one calculated by SSSP algo, by connecting that extra edge, with weight 'w', between two nodes which are not already connected.
Here's an image. As according to SSSP the shortest path between A(source) & D(destination)is A-B-C-D i.e. total of 8.
But given the extra edge. It can be connected between A and D, which are not already connected, to minimize the shortest path yielded through SSSP algo.
Image of graph with extra edge contributing the shortest path
I tried thinking about the solution. But nothing struck so far. I've implemented the Dijkstra algorithm to find the shortest path. But this little modification has baffled me. So can you help a little bit.
There are two options:
We don't need an extra edge. This case is handled by a standard Dijkstra algorithm.
A shortest path with an extra edge looks like this: shortest_path(start, V) + (V, U) + shortest_path(U, target). That is, we go from the start to some vertex V by the shortest path in the original graph, then we go to U (again, an arbitrary vertex) by adding this extra edge (V and U mustn't be connected) and then we go from U to the target node by the shortest path in the original graph.
We can use the structure of the path to get an O(n ^ 2) solution: we can compute shortest paths from the start node to all the others (one run of the Dijkstra's algorithm) and all shortest paths from the target node to all other nodes (one more run). Now we can just iterate over all possible pairs (V, U) and pick the best one.
Bonus: we can solve it in O(m log n) for a sparse graph. The idea is as follows: instead of checking all (U, V) pairs, we can find such U that it has the minimal distance to the target among all vertices that are not connected to V in degree(V) * log V (or even linear) time (this problem is known as finding the smallest element not in the set).
i am not sure I ubderstand your question. You Have a weighted graph ,and can add a edge with w, add to where make shortest path.
I think we can use spfa + dp to solve the problem. Set all other edge to w and create boolean matrix m, m[i,j] =1 mean no edge between i,j, dp[u,0] mean shortest distance when we reach u without using an extra edge, dp[u,1]mean using an extra edge. I don’t write the dp transfer equation. So we can iterate in spfa, and we can also backtrack the best way of dp and get where to set an extra edge.
We do not use Dijkstra algorithm in above solution.
spfa is also a Single Source Shourtest Path algoritm, it can deal negative weighted edge, but not negative cycle.
It’s just my think,i have not try it.but I think it’s a idea to solve it.
If any wrong, tell me please.

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

Dijkstra's algorithm with negative edges on a directed graph

What if the only negative edge costs are coming from the initial node? Will the algorithm still work?
I feel like yes, because I can't think of a counter-example, but I'm having trouble proving it. Is there a counter-example?
Negative edges are a problem for Dijkstra's because there's no guarantee that the edge you pick produces the shortest path if there is an edge you can pick later that is largely negatively weighted. But if the only negative edges are coming out of the initial node, I don't see the problem.
I'm not looking for an algorithm. I'm looking for some insight into the Dijkstra's.
I'm talking about a directed graph, if that makes a difference.
The trouble with having a negative-cost edge is that you can go back and forth along it as many times as you like.
If you impose a rule that an edge may not be used more than once, you still have a problem. Dijkstra's algorithm involves marking a node as "visited", when it's distance from the initial node is considered know once and for all. This happens before all of the edges have been examined; the shortest path from the initial node to node X has been found, all other paths from the initial node are already longer than that, nothing that is discovered later can make those paths shorter. But if there are negative-cost edges somewhere, then a later discovery can make a path shorter, so it may be that a shorter path exists which Dijkstra will not discover.
If only the edges that connect to the initial node may have negative costs, then you still have problem, because the shortest path might involve revisiting the initial node to take advantage of the negative costs, something Dijkstra cannot do.
If you impose another rule that a node may not be visited more than once, then Dijkstra's algorithm works. Notice that in Dijkstra's algorithm, the initial node is given an initial distance of zero. If you give it some other initial distance, the algorithm will still find the shortest path-- but all of the distances will be off by that same amount. (If you want the real distance at the end, you must subtract the value you put in.)
So take your graph, call it A, find the smallest cost of any edge connected to the initial node, call it k which will be negative in this case).
Make a new graph B which you get by subtracting k from the cost of each edge connected to the initial node. Note that all of these costs are now non-negative. So Dijkstra works on B. Also note that the shortest path in B is also the shortest path in A.
Assign the initial node of B the distance k, then run Dijkstra (this will give the same path as running with an initial distance of zero). Compare this to running Dijkstra naively on A: once you leave the initial node everything's the same in the two graphs. The distances are the same, the decisions are the same, the two will produce the same path. And in the case of A the distace will be correct, since it started at zero.
Counter-example:
Graph G = (V, E), with vertices V = {A, B}, edges E = {(A, B), (B, A)} and weight function w(A, B) = -2, w(B, A) = +1.
There's a negative weight cycle, hence minimum distances are undefined (even using A as initial node).
Dijkstra's algorithm doesn't produce correct answer for graph with negative edge weights (even if graph doesn't have any negative weight cycle). For e.g. it computes incorrect shortest path value between (A, C) for following graph with source vertex A,
A -> B : 6
A -> C : 5
B -> D : 2
B -> E : 1
D -> E : -5
E -> C : -2

Resources