Find shortest path between two nodes in directed weighted graph - algorithm

I have a directed weighted graph G = <V, E>. I need to find shortest path between s and t in O((V + E)*logV). It would be a really simple task, if I have a classical metric weight of path. But it is not.
Weight of path = two heaviest edges in this path.
Therefore, classic Dijkstra's algorithm with modified binary heap does not work. I think, that I have to modify this algorithm. I'm trying to do it, but I have no success.
Example.
Weight of path between 3 and 5 = 4 + 2 = 6
Weight of path between 3 and 7 = 4 + 4 = 8

Edited my answer based on counter example by David Eisenstat.
The example you give in your question is not a good example of when Dijkstra will not work.
I believe you can do this by modifying Dijkstra. The key is to keep track of multiple alternatives for each Vertex. Not only do you have to store the weigths that make up the shortest path, you also have to store alternatives where max < shortest.max and min > shortest.min.
Dijkstra is greedy, so what you have to figure out is: is it possible that once a shortest path is determined, another path can be found that turns out to be shorter. Because you will discover paths in increasing length, this is not possible.

Related

Why do we need to perform topological ordering first to find shortest path in a weighted DAG?

My textbook has an excerpt that says one should perform topological sorting to get the vertices in order before finding the shortest path between s and t:
I don't understand why this is a necessary step to find the shortest path in a weighted DAG. Can't we just start at s, and use BFS to explore its neighbors, recording the minimum distance to each vertex?
Or in other words: What would happen if we tried to find the shortest path without first performing topological ordering?
Let's consider a vertex u that is in a topoligically sorted sequence. Topoligical sorting guarantees that every incoming edge to u is already considered, therefore we already know the shortest path to u and now we are able to find the shortest path to the next vertex and so on till the bottom vertex will be reached.
I was earlier too confused that why one cannot do simple bfs/dfs for getting single source shortest distance. But after so much research, my doubt has resolved and therefore I am here for pulling you out of this trouble.
Simple bfs/dfs will work absoluety fine in most cases but not in all cases.
For instance, try to find answer using simple bfs/dfs(source is 0).Find distances from 0 to all nodes.
ADJ LIST:
N W
0->[1,5][2,2]
1->[3,1]
2->[1,1][3,7]
N=NODE
W=WEIGHT TO
REACH THERE
Your answer will be-[0,3,2,6] which is not correct.
Why the test case failed?
Here we created a queue and pushed 0 ,updated its distance as 0 and through adjacency list found its neighbours which are 1 and 2 ,updated dist as 5 and 2 respectively,pushed them in queue.
Then went to 1,found its neighbours which is 3, updated dist as dist[1]+weight[1][3]=5+1=6.Pushed 3 in queue.
Then went to 2(present in queue)updated distance of 1 as dist[2]+weight[2][1]=3 .Checked dist of 3 as dist[2]+weight[2][3]=2+7=9,as the dist was greater than previous dist we do not updated it.But here we missed that dist of 1 has changed and because of that dist of all nodes attached to 1 has changed but we haven't done that.
Thus it is important to note that topological sort will ensure that if u->v, u should be computed before v which will update distance of v every time when prev dist[v]> dist[u]+weight to reach there.Hence will get correct shortest distance.

Shortest path with another constraint

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.

Get path in graph with weighted vertices and edges

If i have the following undirected graph with weighted vertices and edges:
I am trying to come up with a ruby algorithm to find a best shortest path within a defined limit (sum of edges) with the highest value (sum of vertices).
The start point will also be the ending point.
for e.g. finding a path with a maximum of 20 with the highest total value.
This problem seems like a np hard problem and it is hard to find the best solution.
Is there a modified algorithm of dijkstra? I tried using a greedy algorithm but it did not give me a optimal solution. and by using bruteforce on all poosible path will work, but it will take very long if the number of nodes increases.
Was wondering if there is any combination of algorithms that i can use to improve my solution?
Thanks.
You can find an example of Djikstra's algorithm here. What I would do is add a variable to count the number of vertices in the shortest path, and evaluate if the shortest path has too many vertices or is too long once determining what the shortest path even is.
The problem is actually NP hard, you can prove this doing a reduction of Hamiltonian path problem to this problem. Basically given an input for the Hamiltonian path problem (we can stay with the undirected graph) you can create an input for the problem you describe if follow this steps:
build a new graph
create a new graph that is the same that receive the Hamiltonian path problem but give to each vertex and edge weight 1.
create an input for your problem
Pass to your problem the graph just created in the previous step and limit equals to infinity.
Notice now that the result given by your problem is a path as longest as posible with respect at the number of vertex, since the limit restriction is an upper bound in the sum of weight of the edges. This mean that you can add as vertex as posible and still complaint the limit restriction.
How many vertex are in the path determine the total value of this (count of vertex in the path) since the weight is 1 for all of them. So the resulting path is the longest posible in the graph. With this insight we can verify if this path is a hamiltonian path, just check the length of the path. If the path is of length N where N is the number of nodes in the graph there is a hamiltonian path otherwise there isn't.
To solve the problem you can use an approach similar to Bellman-Ford with some modifications. First create a matrix A[i, j] where you storage all the highest total value paths that ends with j and has length (number of edges) i. This is the key, you can't just storage one of this path, because in the next step you need to check all of them to make a relax, here is where the implementation become non-polynomial. The relax technique in the step i iterate through all the storage path in A[i-1, u] and try to improve the value in A[i, v] saving the new paths that actually do it (you must check for >= when try to improve A[i, v] in order to get all the paths), of course this relax take into account the limit restriction. If you uses a global max and a global path and update it in each relax process, you end with the highest value path for the entire graph.

Shortest path that visits all vertices in a directed complete weighted graph

Given: complete directed weighted graph. All weights are positive. Is there any simple way (heuristics?) to find the shortest (in terms of weights) path that visits all vertices? Number of vertices is around 25.
This problem seems to be close to Asymmetric Travelling Salesman, but I don't require this path to be the cycle.
I would recommend K-shortest path approach:
http://www.mathworks.com/matlabcentral/fileexchange/32513-k-shortest-path-yen-s-algorithm
I think this is your best bet... Here is an example: lets say you have 8 nodes and need to get from node 1 to node 8 in the shortest path possible. Let's assume all nodes are connected to each other (i.e., node 1 is connected to node 2:8, and so on). You will have to generate the "cost matrix" based on your problem.
costMatrix = rand(8);
[shortestPath, cost] = dijkstra(costMatrix,1,8);
% Alternatively, return the 10 shortest paths from point 1 to 8:
[shortestPaths, costs] = kShortestPath(costMatrix,1,8,10);
Position (i,j) in the cost matrix is the cost of traveling from node i to node j. If costMatrix(i,j) = inf; there is no connection between node i and node j.
After looking into hidden markov models, I found a number of potential problems - the emission matrix would be difficult to define and you can run into problems where you would enter a "state" two or more times during a single "route." With the k-shortest path, this error doesn't occur.

Shortest path in absence of the given edge

Suppose we are given a weighted graph G(V,E).
The graph contains N vertices (Numbered from 0 to N-1) and M Bidirectional edges .
Each edge(vi,vj) has postive distance d (ie the distance between the two vertex vivj is d)
There is atmost one edge between any two vertex and also there is no self loop (ie.no edge connect a vertex to
itself.)
Also we are given S the source vertex and D the destination vertex.
let Q be the number of queries,each queries contains one edge e(x,y).
For each query,We have to find the shortest path from the source S to Destination D, assuming that edge (x,y) is absent in original graph.
If no any path exists from S to D ,then we have to print No.
Constraints are high 0<=(N,Q,M)<=25000
How to solve this problem efficiently?
Till now what i did is implemented the simple Dijakstra algorithm.
For each Query Q ,everytime i am assigning (x,y) to Infinity
and finding Dijakstra shortest path.
But this approach will be very slow as overall complexity will be Q(time complexity of Dijastra Shortes path)*
Example::
N=6,M=9
S=0 ,D=5
(u,v,cost(u,v))
0 2 4
3 5 8
3 4 1
2 3 1
0 1 1
4 5 1
2 4 5
1 2 1
1 3 3
Total Queries =6
Query edge=(0,1) Answer=7
Query edge=(0,2) Answer=5
Query edge=(1,3) Answer=5
Query edge=(2,3) Answer=6
Query edge=(4,5) Answer=11
Query edge=(3,4) Answer=8
First, compute the shortest path tree from source node to destination.
Second, loop over all the queries and cut the shortest path at the edge specified by the query; this defines a min-cut problem, where you have the distance between the source node and the frontier of one partition and the frontier of the another and the destination; you can compute this problem very easily, at most O(|E|).
Thus, this algorithm requires O(Q|E| + |V|log|V|), asymptotically faster than the naïve solution when |V|log|V| > |E|.
This solution reuses Dijkstra's computation, but still processes each query individually, so perhaps there are room to improvements by exploiting the work did in a previous query in successive queries by observing the shape of the cut induced by the edge.
For each query the graph changes only very slightly, so you can reuse a lot of your computation.
I suggest the following approach:
Compute the shortest path from S to all other nodes (Dijkstras Algorithm does that for you already). This will give you a shortest path tree T.
For each query, take this tree, pruned by the edge (x,y) from the query. This might be the original tree (if (x,y) was no where on the tree) or a smaller tree T'.
If D is in the T', you can take the original shortest path
Otherwise start Dijkstra, but use the labels you already have from the T' (these paths are already smallest) as permanent labels.
If you run the Dijkstra in step 2 you can reuse the pruned of part of tree T in the following way: Every time you want to mark a node permanent (which is one of the nodes not in T') you may attach the entire subtree of this node (from the original tree T) to your new shortest path tree and label all its nodes permanent.
This way you reuse as much information as possible from the first shortest path run.
In your example this would mean:
Compute shortest path tree:
0->1->2->3->4->5
(in this case a very simple)
Now assume we get query (1,2).
We prune edge (1,2) leaving us with
0->1
From there we start Dijkstra getting 2 and 3 as next permanent marked nodes.
We connect 1 to 2 and 1 to 3 in the new shortest path tree and attach the old subtree from 3:
2<-0->1->3->4->5
So we got the shortest path with just running one additional step of Dijkstras Algorithm.
The correctness of the algorithm follows from all paths in tree T being at most as long as in the new Graph from the Query (where every shortest path can only be longer). Therefore we can reuse every path from the tree that is still feasible (i.e. where no edge was removed).
If performance matters a lot, you can improve on the Dijkstra performance through a lot of implementation tricks. A good entry point for this might be the DIMACS Shortest Path Implementation Challenge.
One simple optimization: first run Dijkstra on complete graph (with no edges removed).
Then, for each query - check if the requested edge belongs to that shortest path. If not - removing this edge won't make any difference.

Resources