Dijsktra's Algorithm to accept a single negative edge - algorithm

So I've been working with Dijkstra's algorithm and directed graphs a lot lately. However, I can't seem to figure this out and it's really starting to bother me.
Show how to modify Dijkstra’s algorithm to solve the single source shortest
path problem if there is exactly one negative weight edge but no negative
weight cycles.
So far my initial thought has been to somehow split up the graphs and perform the algorithm separately, but that's about all I've thought of.
I've actually found an explanation I'm looking for, but I can't seem to follow his explanation
Well answered! I'd like to point out that if the number of negative edges is limited, there are Dijkstra-based algorithms that might do a better job. For example, if there is only one negative edge from u to v, you could run Dijkstra on s and on v, and then take the minimum for each vertex between d[s] and d[s]+w(u, v)+d[v], giving a complexity of running Dijkstra twice

Remove the negative edge (u, v), run Dijkstra twice: once starting at s (D1) and once starting at v (D2)
The shortest path between s and t is: min(D1[t], D1[u]+D2[t]+w(u, v)).

Related

Find all cyclic paths in a directed graph

The title is self explanatory. Here's a solution that I found in the internet that can help do this. Here's the link
I don't understand why not visiting a vertex having weight below the given threshold will solve the problem.
Additionally, I have no idea how to solve this using/not using this.
Let's restrict this to simple cycles - those which contain no subcycles. For each node in the graph, begin a depth-first search for that node. record each branch of the recursion tree which results in a match. While searching, never cross over nodes already traversed in the branch.
Consider the complete directed graph on n vertices. There are n(n-1) arcs and n! simple cycles of length n. The algorithm above isn't much worse than this at all. Simply constructing a new copy of the answer would take nearly as much time as running the above algorithm to do it, in the worst case at least.
If you want to find cycles in a directed (or even undirected) graph there is an intuitive way to do it:
For each edge (u, v) in the graph
1. Temporarily ignore the edge (u, v) in step 2
2. Run an algorithm to find all paths from v to u (using a backtrackig algorithm)
3. Output the computed paths in step 2 along with the edge (u, v) as cycles in the graph
Note that you will get duplicate cycles this way since a cycle of length k will be found k times.
You can play with this idea to find cycles with specific properties, as well. For example, if you are aiming to find the shortest weighted cycle in the graph instead of finding all cycles. You can use a Dijkstra in step 2, and take the minimum over all the cycles you find. If you wanna finding the cycle with the least number of edges you can use a BFS in step 2.
If you are more struggling with finding all paths in a graph, this question might help you. Although it's for a slightly different problem.
Counting/finding paths with backtracking

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.

What modifications could you make to a graph to allow Dijkstra's algorithm to work on it?

So I've been thinking, without resorting to another algorithm, what modifications could you make to a graph to allow Dijkstra's algorithm to work on it, and still get the correct answer at the end of the day? If it's even possible at all?
I first thought of adding a constant equal to the most negative weight to all weights, but I found that that will mess up everthing and change the original single source path.
Then, I thought of traversing through the graph, putting all weights that are less than zero into an array or somwthing of the sort and then multiplying it by -1. I think his would work (disregarding running time constraints) but maybe I'm looking at the wrong way.
EDIT:
Another idea. How about permanently setting all negative weights to infinity. that way ensuring that they are ignored?
So I just want to hear some opinions on this; what do you guys think?
Seems you looking for something similar to Johnson's algorithm:
First, a new node q is added to the graph, connected by zero-weight edges to each of the other nodes.
Second, the Bellman–Ford algorithm is used, starting from the new vertex q, to find for each vertex v the minimum weight h(v) of a path
from q to v. If this step detects a negative cycle, the algorithm is
terminated.
Next the edges of the original graph are reweighted using the values computed by the Bellman–Ford algorithm: an edge from u to v,
having length w(u,v), is given the new length w(u,v) + h(u) − h(v).
Finally, q is removed, and Dijkstra's algorithm is used to find the shortest paths from each node s to every other vertex in the
reweighted graph.
By any algorithm, you should check for negative cycles, and if there isn't negative cycle, find the shortest path.
In your case you need to run Dijkstra's algorithm one time. Also note that in Johnson's algorithm semi Bellman–Ford algorithm runs just for new added node. (not all vertices).

Reduction algorithm from the Hamiltonian cycle

I believe that the Hamiltonian cycle problem can be summed up as the following:
Given an undirected graph G = (V, E), a
Hamiltonian circuit is a tour in G passing through
every vertex of G once and only once.
Now, what I would like to do is reduce my problem to this. My problem is:
Given a weighted undirected graph G, integer k, and vertices u, v
both in G, is there a simple path in G from u to v
with total weight of AT LEAST k?
So knowing that the Hamiltonian cycle problem is NP-complete, by reducing this problem to the Hamiltonian, this problem is also proved NP-complete. My issue is the function reducing it to Hamiltonian.
The big issue is that the Hamiltonian problem does not deal with edge weights, so I must convert my graph to one that doesn't have any weights.
On top of that, this problem has a designated start and finish (u and v), whereas the Hamiltonian finds a cycle, so any start is the same as the finish.
For (1), I am thinking along the lines of passing a graph with all simple paths of total weight LESS THAN k taken out.
For (2), I am thinking that this is not really an issue, because if there is a Hamiltonian cycle, then the simple path from u to v can be sliced out of it.
So, my real questions are:
Is my solution going to give me the right answer?
If yes, then how can I take out the edges that will produce simple paths of total weight less than k WITHOUT affecting the possibility that one of those edges may be required for the actual solution? Because if an edge e is taken out because it produces a simple path of weight < k for a subset of E, it can still be used in a simple path with a different combination of edges to produce a path of weight >= k.
Thanks!
Your reduction is in the wrong direction. To show that your problem is NP-complete, you need to reduce Hamilton Circuit to it, and that is very easy. I.e. show that every Hamilton Circuit problem can be expressed in terms of your problem variant.
More of a hint than an answer:
A unweighted graph can be interpreted as a weighted graph where each edge has weight 1. What would the cost of a Hamiltonian cycle be in a graph like that?
The part about the mismatch between cycles and paths is correct and is a problem you need to solve. Basically you need to prove that the Hamiltonian Path problem is also NP complete (a relatively straightfoward reduction to the Cycle problem)
As for the other part, you are doing things in the wrong direction. You need to show that your more complicated problem can solve the Hamiltonian Path problem (and is thus NP-hard). To do this you just basically have to use the special case of unit-cost edges.

Negative weights using Dijkstra's Algorithm

I am trying to understand why Dijkstra's algorithm will not work with negative weights. Reading an example on Shortest Paths, I am trying to figure out the following scenario:
2
A-------B
\ /
3 \ / -2
\ /
C
From the website:
Assuming the edges are all directed from left to right, If we start
with A, Dijkstra's algorithm will choose the edge (A,x) minimizing
d(A,A)+length(edge), namely (A,B). It then sets d(A,B)=2 and chooses
another edge (y,C) minimizing d(A,y)+d(y,C); the only choice is (A,C)
and it sets d(A,C)=3. But it never finds the shortest path from A to
B, via C, with total length 1.
I can not understand why using the following implementation of Dijkstra, d[B] will not be updated to 1 (When the algorithm reaches vertex C, it will run a relax on B, see that the d[B] equals to 2, and therefore update its value to 1).
Dijkstra(G, w, s) {
Initialize-Single-Source(G, s)
S ← Ø
Q ← V[G]//priority queue by d[v]
while Q ≠ Ø do
u ← Extract-Min(Q)
S ← S U {u}
for each vertex v in Adj[u] do
Relax(u, v)
}
Initialize-Single-Source(G, s) {
for each vertex v  V(G)
d[v] ← ∞
π[v] ← NIL
d[s] ← 0
}
Relax(u, v) {
//update only if we found a strictly shortest path
if d[v] > d[u] + w(u,v)
d[v] ← d[u] + w(u,v)
π[v] ← u
Update(Q, v)
}
Thanks,
Meir
The algorithm you have suggested will indeed find the shortest path in this graph, but not all graphs in general. For example, consider this graph:
Let's trace through the execution of your algorithm.
First, you set d(A) to 0 and the other distances to ∞.
You then expand out node A, setting d(B) to 1, d(C) to 0, and d(D) to 99.
Next, you expand out C, with no net changes.
You then expand out B, which has no effect.
Finally, you expand D, which changes d(B) to -201.
Notice that at the end of this, though, that d(C) is still 0, even though the shortest path to C has length -200. This means that your algorithm doesn't compute the correct distances to all the nodes. Moreover, even if you were to store back pointers saying how to get from each node to the start node A, you'd end taking the wrong path back from C to A.
The reason for this is that Dijkstra's algorithm (and your algorithm) are greedy algorithms that assume that once they've computed the distance to some node, the distance found must be the optimal distance. In other words, the algorithm doesn't allow itself to take the distance of a node it has expanded and change what that distance is. In the case of negative edges, your algorithm, and Dijkstra's algorithm, can be "surprised" by seeing a negative-cost edge that would indeed decrease the cost of the best path from the starting node to some other node.
Note, that Dijkstra works even for negative weights, if the Graph has no negative cycles, i.e. cycles whose summed up weight is less than zero.
Of course one might ask, why in the example made by templatetypedef Dijkstra fails even though there are no negative cycles, infact not even cycles. That is because he is using another stop criterion, that holds the algorithm as soon as the target node is reached (or all nodes have been settled once, he did not specify that exactly). In a graph without negative weights this works fine.
If one is using the alternative stop criterion, which stops the algorithm when the priority-queue (heap) runs empty (this stop criterion was also used in the question), then dijkstra will find the correct distance even for graphs with negative weights but without negative cycles.
However, in this case, the asymptotic time bound of dijkstra for graphs without negative cycles is lost. This is because a previously settled node can be reinserted into the heap when a better distance is found due to negative weights. This property is called label correcting.
TL;DR: The answer depends on your implementation. For the pseudo code you posted, it works with negative weights.
Variants of Dijkstra's Algorithm
The key is there are 3 kinds of implementation of Dijkstra's algorithm, but all the answers under this question ignore the differences among these variants.
Using a nested for-loop to relax vertices. This is the easiest way to implement Dijkstra's algorithm. The time complexity is O(V^2).
Priority-queue/heap based implementation + NO re-entrance allowed, where re-entrance means a relaxed vertex can be pushed into the priority-queue again to be relaxed again later.
Priority-queue/heap based implementation + re-entrance allowed.
Version 1 & 2 will fail on graphs with negative weights (if you get the correct answer in such cases, it is just a coincidence), but version 3 still works.
The pseudo code posted under the original problem is the version 3 above, so it works with negative weights.
Here is a good reference from Algorithm (4th edition), which says (and contains the java implementation of version 2 & 3 I mentioned above):
Q. Does Dijkstra's algorithm work with negative weights?
A. Yes and no. There are two shortest paths algorithms known as Dijkstra's algorithm, depending on whether a vertex can be enqueued on the priority queue more than once. When the weights are nonnegative, the two versions coincide (as no vertex will be enqueued more than once). The version implemented in DijkstraSP.java (which allows a vertex to be enqueued more than once) is correct in the presence of negative edge weights (but no negative cycles) but its running time is exponential in the worst case. (We note that DijkstraSP.java throws an exception if the edge-weighted digraph has an edge with a negative weight, so that a programmer is not surprised by this exponential behavior.) If we modify DijkstraSP.java so that a vertex cannot be enqueued more than once (e.g., using a marked[] array to mark those vertices that have been relaxed), then the algorithm is guaranteed to run in E log V time but it may yield incorrect results when there are edges with negative weights.
For more implementation details and the connection of version 3 with Bellman-Ford algorithm, please see this answer from zhihu. It is also my answer (but in Chinese). Currently I don't have time to translate it into English. I really appreciate it if someone could do this and edit this answer on stackoverflow.
you did not use S anywhere in your algorithm (besides modifying it). the idea of dijkstra is once a vertex is on S, it will not be modified ever again. in this case, once B is inside S, you will not reach it again via C.
this fact ensures the complexity of O(E+VlogV) [otherwise, you will repeat edges more then once, and vertices more then once]
in other words, the algorithm you posted, might not be in O(E+VlogV), as promised by dijkstra's algorithm.
Since Dijkstra is a Greedy approach, once a vertice is marked as visited for this loop, it would never be reevaluated again even if there's another path with less cost to reach it later on. And such issue could only happen when negative edges exist in the graph.
A greedy algorithm, as the name suggests, always makes the choice that seems to be the best at that moment. Assume that you have an objective function that needs to be optimized (either maximized or minimized) at a given point. A Greedy algorithm makes greedy choices at each step to ensure that the objective function is optimized. The Greedy algorithm has only one shot to compute the optimal solution so that it never goes back and reverses the decision.
Consider what happens if you go back and forth between B and C...voila
(relevant only if the graph is not directed)
Edited:
I believe the problem has to do with the fact that the path with AC* can only be better than AB with the existence of negative weight edges, so it doesn't matter where you go after AC, with the assumption of non-negative weight edges it is impossible to find a path better than AB once you chose to reach B after going AC.
"2) Can we use Dijksra’s algorithm for shortest paths for graphs with negative weights – one idea can be, calculate the minimum weight value, add a positive value (equal to absolute value of minimum weight value) to all weights and run the Dijksra’s algorithm for the modified graph. Will this algorithm work?"
This absolutely doesn't work unless all shortest paths have same length. For example given a shortest path of length two edges, and after adding absolute value to each edge, then the total path cost is increased by 2 * |max negative weight|. On the other hand another path of length three edges, so the path cost is increased by 3 * |max negative weight|. Hence, all distinct paths are increased by different amounts.
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.
I will be just combining all of the comments to give a better understanding of this problem.
There can be two ways of using Dijkstra's algorithms :
Marking the nodes that have already found the minimum distance from the source (faster algorithm since we won't be revisiting nodes whose shortest path have been found already)
Not marking the nodes that have already found the minimum distance from the source (a bit slower than the above)
Now the question arises, what if we don't mark the nodes so that we can find shortest path including those containing negative weights ?
The answer is simple. Consider a case when you only have negative weights in the graph:
)
Now, if you start from the node 0 (Source), you will have steps as (here I'm not marking the nodes):
0->0 as 0, 0->1 as inf , 0->2 as inf in the beginning
0->1 as -1
0->2 as -5
0->0 as -8 (since we are not relaxing nodes)
0->1 as -9 .. and so on
This loop will go on forever, therefore Dijkstra's algorithm fails to find the minimum distance in case of negative weights (considering all the cases).
That's why Bellman Ford Algo is used to find the shortest path in case of negative weights, as it will stop the loop in case of negative cycle.

Resources