Related
I'm trying to apply Djikstra's algorithm on this graph from my textbook, but I keep getting stuck on vertex A when trying to traverse from G->C. Here is the link to the graph image:
LINK
I'll outline my steps below:
I start at the initial vertex(G).
A receives a cost of 6, E receives a cost of 1, H receives a cost of 4 since they are all initially infinity. G is marked as visited.
I go to the neighbor with the shortest cost; in this case its E.
At E, I set the cost of B as 1 + 2 = 3, and the cost of F as 1 + 2 = 3. E is then marked as visited.
I visit the neighbor of E with the lowest cost: This is where I start to get stuck since both B and F have the same cost. Assume that I choose B.
At B, I set the cost of C as 3 + 7 = 10 and the cost of A as 5.
Now A is the neighbor with the lowest cost but accessing it makes me stuck since I can't get out.
I'd really appreciate some suggestions or corrections if I am approaching it wrong.
Since G has already been marked as visited, this node is no longer considered and thus A is also considered, since there are no more possible connections.
At step 6 the nodes that have been visited are G, E and B. Now you have to pick the node with the minimum distance value, which is F. So the flaw in step 7 is really the assumption that it has to be a neighbour node.
Continuing from step 7:
Pick F. Update C's distance to 6. Mark F visited.
Pick H. Update D's distance to 6. Mark H visited.
Now pick A. No updates required. Mark A visited.
Pick C or D in any order and mark them visited as well. No updates required here.
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
Given a weighted undirected graph, I need to find the shortest path between two nodes, a classical shortest path problem actually. But there is one more constraint : Each node contains a "reduction" value that can be used to reduce the cost of the following edges for one traversal(not only adjacent, and reduction are not cumulative). So you can reduce the cost of an edge using the "Reduction" that was in one of the node you went throught before (the final cost for each edge can't be less than 0).
Note that once we went throught a node with a reduction, we can use it again for all the following edges (not just adjacent, and it is available an unlimited amount of time). Reduction doesn't accumulate.
Let's consider this graph :
in this graph the shortest path from node 1 to 5 is :
1 -> 4 for a cost of 13 (15-2)
4 -> 3 for a cost of 0 (12-12)
3 -> 5 for a cost of 0 (10-12) In this case, we reuse the reduction of node 4 because it is bigger than the reduction of node 3 (We went throught the node n°4 then we have an unlimited amount of reduction of cost 12). It is 0 and not -2 because the weight of an edge can't be negative.
Then the total cost from node 1 to node 5 is 13 + 0 + 0 = 13
To solve this problem, I've tried to use the classical Dijkstra/Bellman-Ford but it didn't work, can you help me with this ?
It seems to be this can be solved with a variation of Bellman-Ford.
Every path up to a given node can be summarised as a pair (C, D) where C is the cost of that path (after discounts) and D is the best discount factor available on that path. Since a discount can be reused an unlimited number of times once that node has been visited, it makes sense to always use the biggest discount seen so far on that path. For example, the path (1 -> 4 -> 3) has cost C = 13 and discount D = 12.
The complication over the undiscounted problem is that we cannot tell from the cost what the "best" path is to nodes in between the source and destination. In your example the path (1 -> 2 -> 3) has lower cost than (1 -> 4 -> 3), but the latter has a better discount which is why the best path from 1 to 5 is (1 -> 4 -> 3 -> 5).
Rather than recording the lowest cost path to each node (in Bellman-Ford algorithm), we need to record all "feasible" paths from the source to that node found so far. A path can be said to be feasible if there is no other known path that has both a lower cost and a better discount. After the algorithm terminates we can take from all feasible paths from source to destination the one with the smallest cost, ignoring the discount.
(Edit: I originally suggested Djikstra could be used but I think that not be so straightforward. I'm not sure we can choose "the closest" unvisited node in any meaningful way such that we are guaranteed to find the minimal path. Someone else might see how to make it work though...)
I think you can use a Dijkstra-type algorithm. Dijkstra's algorithm can be thought of computing the minimum spanning tree that contains the shortest paths from a source vertex to all other vertices. Let's call this the "Dijkstra tree" that contains all the shortest paths from a given source vertex.
Dijkstra keeps adding new vertices to the current tree. For the next vertex he chooses the one that is closest to the current tree. See this animation from wikipedia:
So when Dijkstra adds a new vertex v to an already inserted vertex u (of the current tree), the edge weight of {u, v} has to be considered. In your case, the costs are not just the edge weight of {u, v}, but the weight reduced by the sum of vertex-reductions along the shortest path to u in the current tree. So you have to remember the sum of the vertex reductions along the paths of this "Dijkstra" tree in the vertices.
I'm trying to solve this problem using an algorithm for at least a week but to no avail. I have a set of roads (1,2,3,...) and for each road there can be at least 1 vehicle that can pass (A,B,C,...). My problem is how to get the least number of rides for one to take to reach one road to another. For example:
road | vehicle(s)
1 | A,B
2 | A,B,C
3 | C,D
4 | C,D
5 | D,E
The output should be:
from 1, ride A or B to 2
from 2, ride C to 4
from 4, ride D to 5
The policy here is to exhaust one ride as much as possible, but the output should have the least number of ride changes.
Example 2:
road | vehicle(s)
1 | A,B
2 | A,B,C
3 | C,D
4 | C,D
5 | A,E
6 | E,F
7 | F
8 | F,H
9 | F,G
10 | F,G
11 | F
12 | F,G
13 | G,H
14 | H
Output:
from 1, ride A to 5
from 5, ride E to 6
from 6, ride F to 8
from 8, ride H to 14
Please help me to write the algorithm for the problem. I need to solve this for my project. Thanks!
PS: If you need other examples or clarification, just tell me in the comments below.
One way to think about this problem is to model it as a graph search problem. For each of the different vehicles v, construct a graph Gv whose nodes are all of the roads in the network with arcs between the nodes that are connected by vehicle v. For example, in your first example, the graph GA would have five nodes, of which there is only a connection from node 1 to node 2, while the graph GC would have five nodes with edges from 2 to 3, 3 to 4, and 4 to 2.
Now, consider the final graph G constructed as follows. G is formed by taking all of the graphs Gv for all of the vehicles v (meaning that there are multiple copies of each node in the original graph), then adding edges between corresponding nodes in the different graphs if there are multiple different vehicles that all reach a road. For example, in the graph G for the original problem, you would have G contain subgraphs GA and GB, ..., GE. Since road 1 is serviced by both vehicles A and B, you would add an edge between the nodes for road 1 in the graphs GA and GB, and since road 2 is serviced by vehicles A, B, and C, there would be edges connecting all of the road 2 nodes for subgraphs GA, GB, and GC.
You are interested in minimizing the number of transfers you need to make, and so we'd like to set up some costs in this graph that measure that. In particular, we say that any edge contained completely in one of the subgraphs Gv has cost zero, since once you're on a vehicle of a given type you don't need to make any changes to move around the roads the vehicle services. However, we assign a cost of one to each of the edges linking the subgraphs for different vehicles, since following this sort of edge would mean that you're changing which vehicle you're using. If you now trace out any path in this graph, the total cost of that path is the number of vehicle changes you make.
To finalize the construction, we need to have some way of finding a cost from the starting road to the destination. To do this, we'll add two new nodes s and t to the graph representing the start and end of the journey. Node s will have cost-zero directed edges to the first road of each of the subgraphs, since when you start off the journey you can pick any of the vehicles as your first step. Similarly, every subgraph's node for the final road will have a zero-cost edge to t, since once you arrive at the destination road it doesn't matter what vehicle you're in.
In this setup, any path from s to t has a cost equal to the total number of transfers you need to make. Finding the shortest path in this graph from s to t therefore gives you both the route to take and the cost of that path. You can solve this using Dijkstra's algorithm, for example.
The runtime of this algorithm isn't stellar, but it's still polynomial time. Suppose that there are n roads and m different vehicles. The graph we create will have m different subgraphs in it, each of which is for one vehicle, and in the worst case these graphs have O(n2) edges in them. If we then link together all the corresponding nodes of these subgraphs where you can change lines, then in the worst case there will be O((mn)2) such edges, since there are m graphs of n nodes that all might be connected to one another. We thus have a graph with O(mn) nodes and O((mn)2) edges, so we can run Dijkstra's algorithm in O((mn)2 + mn log mn) time.
The main idea that I think is important to take away from this problem is that you can often solve problems about finding paths in graphs subject to certain constraints by creating a new graph formed out of multiple copies of the old graph and then coming up with a good edge-cost function for that graph.
Hope this helps!
I have a weighted, directed graph with multiples edges starting from the ending at the same nodes.
Ex.
Multiple edges going from node A to node B.
What would be the best search algorithm to get all of the paths to a certain node and the associated costs of these paths?
Since you want all the paths, I'd use a simple breadth-first search. However, I also suggest that you collapse all the parallel edges into a single edge that has a list of weights.
Once you get all the different paths (that is, all the paths in which the nodes visited are different), for each path you can calculate all the possible alternative parallel routes.
So if you've got the following edges:
A -> C (5)
A -> C (3)
A -> B (7)
B -> C (1)
B -> C (4)
The first step transforms it into:
A -> C (5,3)
A -> B (7)
B -> C (1,4)
The breadth-first search on this graph will yield the following paths between A and B:
A -> B (7)
A -> C -> B (5,3) + (1,4)
So for the second path, you'll get the following costs:
5 + 1
5 + 4
3 + 1
3 + 4
This isn't going to be any faster in itself than just doing a BFS on the original graph, but a simpler graph is easier to handle.
If you have to output the cost of each path, there is nothing better than a plain DFS (or BFS). Since the problem is output sensitive and you might just have O(E + V) paths, you cannot accomplish anything better in terms of big-O notation.
As already stated, you can do bruteforce/backtracking using Depth First Search, etc.
Don't expect to find any shortcuts for this - if your graph is dense enough there can be lots of paths and even just finding how many of them there are is #P-complete (ie.: untractable).
(If your problem is different - maybe repeated nodes are allowed or you only want to find the shortest path or something like that then there could be tractable solution)
do you allow the cycling, that is you have directed link/path from a->b b-x-x-->a? for which case you will end up with unlimited paths.