Shortest path with another constraint - algorithm

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.

Related

Shortest cycle in undirected weighted graph which contains every node

Problem: Find the 'shortest cycle in undirected weighted graph which contains every node'. All weights are positive. A node may be visited more than once, the is distinguishes the problem from a Hamiltonian cycle (TSP).
A naïve attempt might be to use the minimum spanning tree (MST) and backtrack to get to the starting node. This results in a length of 2*MST but is not the minimum cycle.
Example: Consider a complete graph with vertices 1,2,3,4 and edge costs c12=c13=c14=1 and c23=c24=c34=100. TSP distance = 202 (1 -> 2 -> 3 -> 4 -> 1). Shortest cycle distance = 6 (1 -> 2 -> 1 -> 3 -> 1 -> 4 -> 1)
Edit: I am looking for an algorithm to find the shortest cycle.
In the Wikipedia page on TSP, it mentions a special case called "metric TSP", in which distances satisfy the triangle inequality.
In metric TSP, it does not matter whether or not you can visit the same city twice, because doing so is never necessary. You can always easily remove all the repeated visits without making your path any longer.
Every instance of "metric TSP" is, therefore, an instance of your problem. Metric TSP is still NP-hard, so your problem is too.

How to weight other factors when using Dijkstra

I'm solving this problem where we have a graph, and are trying to get from node 1 to node N. The edge weights are the "cost" and each edge also has a "flow" value. For any path from node 1 to node N, the total cost would be the sum of all the costs of the edges on the path, and the flow would be the minimum flow value among the edges. We want to maximize the ratio of flow/cost.
I had the idea to use Dijkstra to find the smallest cost path from 1 to N, and when I tried finding the path this way I realized I wasn't accounting for flow. I want to perform modified Dijkstra where I take into account the flow of each edge when calculating the best path, but I'm not sure how to do this.
Should I manipulate the edge costs by subtracting or adding extra flow, or would this not work because we are looking at the ratio?
I also tried finding every path through BFS, but there is a time constraint and I am unable to do that as well.
Could anyone give me some tips on how to solve this problem?
Edit:
An example is having 3 nodes, 1, 2, and 3. 1 and 2 have an edge cost of 2, and a flow of 4. 2 and 3 have an edge cost of 5, and a flow of 3. In this example, there is only one path from 1 to N. Its flow is min(3,4)=3 and its cost is 2+5=7. So the ratio would be 3/7. But in most cases we will have several possible paths.
Follow Dijkstra's algorithm and maintain for each node v a distance label D[v] (as usual), and additionally a flow label F[v]. The goal is to maximize the ratio F[v] / D[v]. The vertex u the algorithm should select next is the one which maximizes this ratio.
Then, during the relaxation of any incident edge e=(u,v), perform the following computation to see if the ratio of a new possible path from the starting vertex to v that uses u as an intermediate vertex is better than any previously found path.
// relaxing edge e = (u,v)
newDistance = min{ D[u], D[v] + cost(e) }
newFlow = min{ F[u], flow(e) }
if ( (newFlow / newDistance) > (F[v] / D[v]) )
v.parent = u
F[v] = newFlow
D[v] = newDistance
I'm not completely sure, but you can just use your flow/cost ration as a node weight. It's ok for Dijkstra algorithm.
By the way, I've got a coursework on the same topic, I've got length and speed costs, and using length/speed ratio worked for me. You can see all the sources on GitHub.

Path with least maximum edge weight

Let's say we have a directed non-negative-weighted graph.
We have to find the least cost path between (u, v).
The cost of a path is defined as the maximum cost of the second most expensive edge that the path contains.
Here's an example.
Graph with 4 nodes and 4 edges:
from 1 to 2 at cost 3
from 1 to 3 at cost 7
from 2 to 3 at cost 5
from 3 to 4 at cost 2
The optimal path between 1 and 4 should be 1 - 3 - 4 with total cost 2 (costs are 2 and 7, the second highest one is 2).
Dijkstra standard SSSP (reconstructing the path and finding the second highest edge) obviously doesn't work.
I've thought at MST (which should be OK) but it's not guaranteed to cover the best path (u,v).
We can get O(E + V log V), which is o(E log E) for sufficiently dense graphs. Using Dijkstra with a Fibonacci heap, compute two max-weight (as opposed to second max-weight) shortest path trees, one directed leafward from the root u, one directed rootward to the root v. For each edge s->t, consider the path consisting of the max-weight shortest path from u to s, the edge s->t, and the max-weight shortest path from t to v, whose second max-weight is bounded by taking the maximum of the u->s and t->v segments.
Consider binary search for the optimum cost. Sort weights of all edges, and search for the least value X satisfying the condition:
There is a u -> v path which has at most one edge with weight greater than X.
How to check the condition? For a given X:
Run DFS from u and find set U of vertices reachable from u using edges of weight at most X. If v is in U, condition is satisfied.
Otherwise find according set V with DFS from v.
The condition is satisfied if and only if there exist an edge with one vertex in U and other in V.
Time complexity: O(E log E).
You can binary search over the answer(sort the edges by their weight before it).
For a fixed answer c, let's call edges with weight > c heavy and other edges light.
So all you need to check is if there is path with at most 1 heavy edge. You can do it by assigning 0 cost to light edges and 1 to heavy ones and running 0-1 bfs. If the distance is <= 1, then it possible to obtain a path with a cost at most c.
The time complexity is O(E log E).

Finding a path in which the difference between min edge cost and max edge cost is minimum across all routes

We have to find the route from a source to a sink in a graph in which the difference between the maximum costing edge and the minimum costing edge is minimum.
I tried using a recursive solution but it would fail in condition of cycles and a modified dijkstra which also failed.
Is there an algorithm where i will not have to find all routes and then find the minimum?
Sort the edges by weight (in non-decreasing order), then for each edge do the next: Add the next edges (the ones with greater or equal weight in non-decreasing order) until the source and sink are connected, then update your answer with de difference between the last edge, like this:
ans = INFINITE
for each Edge e1 in E (sorted by weight in non-decreasing order)
clear the temporal graph
for each Edge e2 in E
if e2.weight >= e1.weight
add e2 to the temporal graph
if sink and source are connected in the temporal graph
ans = min(ans, e2.weight - e1.weight)
break
print ans
If you use the UNION-FIND structure to add edges and check connectivity between source and sink you should get an overall time of O(edges^2)
OK, so you have a graph, and you need to find a path from one node (source) to another (sink) such that max edge weight on the path minus min edge weight on the path is minimized. You don't say whether your graph is directed, can have negative edge weights, or has cycles, so lets assume a "yes" answer to all these questions.
When computing your path "score" (maximum difference between edge weights), we observe these are similar to path distances: you could have a path from A to B that scores higher (undesirable) or lower (desirable). If we treat path scores like path weights we observe that as we build a path by adding new edges, the path score (=weight) can only increase: given a path A->B->C where weight(A->B)=1 and weight(B->C)=5, yielding a path score of 4, if I add edge C->D to the path A->B->C, the path score can only increase or stay the same: the difference between minimum edge weight and maximum edge weight will not be lower than 4.
The conclusion from all of this is that we can explore the graph looking for best paths as if we are looking for optimal path in a graph with no negative edges. However, there could be (and likely to be, given the connectivity described) cycles. This means that Dijkstra's algorithm, properly implemented, will have optimal performance relative to this graph's topology given what we know today.
No solution without full graph exploration
One may be misled into thinking that we can make locally good decisions about which edge should belong to the optimal path without exploring the whole graph. The following subgraph illustrates the problem with this:
Say you've need a path from A to F, and you are at node B. Given everything you know, you'd choose a path to C, as it minimizes the path score. What you don't know (yet) is that the next edge in that path will cause the score of this path to increase substantially. If you knew that you would have chosen the edge B->D as a next element in an optimal path.

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