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).
Related
I am trying to find an intuitive explanation as to why we can generalize Dijkstra's Algorithm to find the K shortest (simple) paths from a single source in a directed, weighted graph with no negative edges. According to Wikipedia, the pseudocode for the modified Dijkstra is as follows:
Definitions:
G(V, E): weighted directed graph, with set of vertices V and set of directed edges E,
w(u, v): cost of directed edge from node u to node v (costs are non-negative).
Links that do not satisfy constraints on the shortest path are removed from the graph
s: the source node
t: the destination node
K: the number of shortest paths to find
P[u]: a path from s to u
B: a heap data structure containing paths
P: set of shortest paths from s to t
count[u]: number of shortest paths found to node u
Algorithm:
P = empty
for all u in V:
count[u] = 0
insert path P[s] = {s} into B with cost 0
while B is not empty:
let P[u] be the shortest cost path in B with cost C
remove P[u] from B
count[u] = count[u] + 1
if count[u] <= K then:
for each vertex v adjacent to u:
let P[v] be a new path with cost C + w(u, v) formed by concatenating edge (u, v) to path P[u]
insert P[v] into B
return P
I know that, for the original Dijkstra's Algorithm, one can prove by induction that when a node is added to the closed set (or popped from a heap if it's implemented in the form of BFS + heap), the cost to that node must be minimum from the source.
This algorithm here seems to be based on the fact that when a node is popped for the ith time from the heap, we have the ith smallest cost to it from the source. Why is this true?
The Wiki article doesn't specify, but that code will only solve the 'loopy' version of k-shortest-paths, where paths are not required to be simple.
The simple path version of the problem is harder: you'll want to look at something like Yen's algorithm, which does clever filtering to avoid repeated points when generating paths. Yen's algorithm can use Dijkstra's algorithm as a subroutine, but any other shortest-path algorithm can also be used instead.
There is no obvious way to modify Dijkstra's algorithm to solve the k-shortest-simple-paths problem. You'd need to track the paths in the priority queue (which is already done in your posted code), but there's an exponential upper bound on the number of times each vertex can be explored.
Here, if count[u] <= K puts an upper bound of K+1 on the number of times a vertex can be explored, which works for the non-simple path case. On the other hand, a direct modification of Dijkstra's algorithm for simple paths would, in the worst case, require you to explore a node once for each of the 2^(V-1) possibilities of which nodes had been previously visited (or possibly a slightly smaller exponential).
Question:
Given a graph of N nodes and M edges, the edges are indexed from 1 -> M. It is guaranteed that there's a path between any 2 nodes.
You need to assign weights for M edges. The weights are in the range of [1...M], and each number can only occur once.
To be shorted, the answer should be a permutation array of [1...M], in which arr[i] = x means edge[i] has the weight of x.
You are given a set R of n-1 edges. R is guaranteed to be a Spanning Tree of the graph.
Find a way to assign weights so that R is the Minimum Spanning Tree of the graph, if there are multiple answers, print the one with minimum lexicographical order.
Contraints:
N, M <= 10^6
Example:
Edges:
3 4
1 2
2 3
1 3
1 4
R = [2, 4, 5]
Answer: 3 4 5 1 2
Explaination:
If you assign weights for the graph like the above image, the MST would be the set R, and it has the smallest lexicographical order.
My take with O(N^2):
Since it asks for the minimum lexicographical order, I traverse through the list of edges, assigning the weights in an increasing order. Intially, w = 1. There can be 3 situations:
If edge[i] is in R, assign weight[i] = w, increase w by 1
If edge[i] is not in R: say edge[i] connect nodes u and v. assign weight and increase w for each edge in the path from u to v in R (if that edge is not assigned yet). Then assign weight and increase w for edge[i]
If edge[i] is assigned, skip it
Is there any way to improve my solution so that it can work in O(N.logN) or less?
Yes, there's an O(m log m)-time algorithm.
The fundamental cycle of a non-tree edge e is comprised of e and the path in the tree between the endpoints of e. Given weights, the spanning tree is minimum if and only if, for every non-tree edge e, the heaviest edge in the fundamental cycle of e is e itself.
The lexicographic objective lends itself to a greedy algorithm, where we find the least valid assignment for edge 1, then edge 2 given edge 1, then edge 3 given the previous edges, etc. Here's the core idea: if the next unassigned edge is a non-tree edge, assign the next numbers to the unassigned tree edges in its fundamental cycle; then assign the next number.
In the example, edge 3-4 is first, and edges 1-3 and 1-4 complete its fundamental cycle. Therefore we assign 1-3 → 1 and 1-4 → 2 and then 3-4 → 3. Next is 1-2, a tree edge, so 1-2 → 4. Finally, 2-3 → 5 (1-2 and 1-3 are already assigned).
To implement this efficiently, we need two ingredients: a way to enumerate the unassigned edges in a fundamental cycle, and a way to assign numbers. My proposal for the former would be to store the spanning tree with the assigned edges contracted. We don't need anything fancy; start by rooting the spanning tree somewhere and running depth-first search to record parent pointers and depths. The fundamental cycle of e will be given by the paths to the least common ancestor of the endpoints of e. To do the contraction, we add a Boolean field indicating whether the parent edge is contracted, then use the path compression trick from disjoint-set forests. The work will be O(m log m) worst case, but O(m) average case. I think there's a strong possibility that the offline least common ancestor algorithms can be plugged in here to get the worst case down to O(m).
As for number assignment, we can handle this in linear time. For each edge, record the index of the edge that caused it to be assigned. At the end, stably bucket sort by this index, breaking ties by putting tree edges before non-tree. This can be done in O(m) time.
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.
Suppose that we are given a directed graph H = (V, E). For each edge e, the weight of the edge, w(e) is either 2, 3 or 5. Modify the BFS so that it will compute the length of the shortest path from a single source vertex s. Explain why your algorithm is correct and determine its worst-case running time (You may assume that H is represented via an adjacency list).
How would you go about this? What makes the specific weight edges different from just any?
You can consider imaginary nodes between the edges. So if between 2 nodes there is an edge of length 2. You make an intermediary node and add edges of length 1 between them. Then use the normal breadth first search. (You also need to do this for nodes of length 3 and 5, adding 2 and 4 nodes). Since you only add a O(E) nodes it's the same complexity.
I'm writing an algorithm for finding the second min cost spanning tree. my idea was as follows:
Use kruskals to find lowest MST.
Delete the lowest cost edge of the MST.
Run kruskals again on the entire graph.
return the new MST.
My question is: Will this work? Is there a better way perhaps to do this?
You can do it in O(V2). First compute the MST using Prim's algorithm (can be done in O(V2)).
Compute max[u, v] = the cost of the maximum cost edge on the (unique) path from u to v in the MST. Can be done in O(V2).
Find an edge (u, v) that's NOT part of the MST that minimizes abs(max[u, v] - weight(u, v)). Can be done in O(E) == O(V2).
Return MST' = MST - {the edge that has max[u, v] weight} + {(u, v)}, which will give you the second best MST.
Here's a link to pseudocode and more detailed explanations.
Consider this case:
------100----
| |
A--1--B--3--C
| |
| 3
| |
2-----D
The MST consists of A-B-D-C (cost 6). The second min cost is A-B-C-D (cost 7). If you delete the lowest cost edge, you will get A-C-B-D (cost 105) instead.
So your idea will not work. I have no better idea though...
You can do this -- try removing the edges of the MST, one at a time from the graph, and run the MST, taking the min from it. So this is similar to yours, except for iterative:
Use Kruskals to find MST.
For each edge in MST:
Remove edge from graph
Calculate MST' on MST
Keep track of smallest MST
Add edge back to graph
Return the smallest MST.
This is similar to Larry's answer.
After finding MST,
For each new_edge =not a edge in MST
Add new_edge to MST.
Find the cycle that is formed.
Find the edge with maximum weight in
cycle that is not the non-MST edge
you added.
Record the weight increase as W_Inc
= w(new_edge) - w(max_weight_edge_in_cycle).
If W_Inc < Min_W_Inc_Seen_So_Far Then
Min_W_Inc_Seen_So_Far = W_Inc
edge_to_add = new_edge
edge_to_remove = max_weight_edge_in_cycle
Solution from following link.
http://web.mit.edu/6.263/www/quiz1-f05-sol.pdf
slight edit to your algo.
Use kruskals to find lowest MST.
for all edges i of MST
Delete edge i of the MST.
Run kruskals again on the entire graph.
loss=cost new edge introduced - cost of edge i
return MST for which loss is minimum
Here is an algorithm which compute the 2nd minimum spanning tree in O(n^2)
First find out the mimimum spanning tree (T). It will take O(n^2) without using heap.
Repeat for every edge e in T. =O(n^2)
Lets say current tree edge is e. This tree edge will divide the tree into two trees, lets say T1 and T-T1. e=(u,v) where u is in T1 and v is in T-T1. =O(n^2)
Repeat for every vertex v in T-T1. =O(n^2)
Select edge e'=(u,v) for all v in T-T1 and e' is in G (original graph) and it is minimum
Calculate the weight of newly formed tree. Lets say W=weight(T)-weight(e)+weight(e')
Select the one T1 which has a minimum weight
Your approach will not work, as it might be the case that min. weight edge in the MST is a bridge (only one edge connecting 2 parts of graph) so deleting this edge from the set will result in 2 new MST as compared to one MST.
based on #IVlad's answer
Detailed explanation of the O(V² log V) algorithm
Find the minimum spanning tree (MST) using Kruskal's (or Prim's) algorithm, save its total weight, and for every node in the MST store its tree neighbors (i.e. the parent and all children) -> O(V² log V)
Compute the maximum edge weight between any two vertices in the minimum spanning tree. Starting from every vertex in the MST, traverse the entire tree with a depth- or breadth-first search by using the tree node neighbor lists computed earlier and store the maximum edge weight encountered so far at every new vertex visited. -> O(V²)
Find the second minimum spanning tree and its total weight. For every edge not belonging to the original MST, try disconnecting the two vertices it connects by removing the tree edge with the maximum weight in between the two vertices, and then reconnecting them with the currently considered vertex (note: the MST should be restored to its original state after every iteration). The total weight can be calculated by subtracting the weight of the removed edge and adding that of the added one. Store the minimum of the total weights obtained.
To practice you could try the competitive programming problem UVa 10600 - ACM Contest and Blackout, which involves finding the second minimum spanning tree in a weighted graph, as asked by the OP. My implementation (in modern C++) can be found here.
MST is a tree which has the minimum weight total of all edges of the graph. Thus, 2nd minimum mst will have the 2nd minimum total weight of all edges in the graph.
let T -> BEST_MST ( sort the edges in the graph , then find MST using kruskal algorithm)
T ' -> 2nd best MST
let's say T has 7 edges , now to find T ' we will one by one remove one of those 7 edges and find a replacement for that edge ( cost of that edge definitely will be greater than the edge we just removed from T ).
let's say original graph has 15 edges
our best MST ( T ) has 7 edges
and 2nd best MST ( T ' ) will also going to have 7 edges only
How to find T '
there are 7 edges in T , now for all those 7 edges remove them one by one and find replacement for those edges .
let's say edges in MST ( T ) --> { a,b,c,d,e,f,g }
let's say our answer will be 2nd_BEST_MST and initially it has infinte value ( i know it doesn't sounds good , let's just assume it for now ).
for all edges in BEST_MST :
current_edge = i
find replacement for that edge, replacement for that edge will definitely going to have have weight more than the ith edge ( one of 7 edges )
how we will going to find the replacement for that edge , using Kruskul algorithm ( we are finding the MST again , so we will use kruskal algorithm only , but this we don't have to sort edges again , because we did it when we were finding the BEST_MST ( T ).
NEW_MST will be generated
2nd_best_MST = min( NEW_MST , 2nd_best_MST )
return 2nd_best_MST
ALGORITHM
let' say orignal graph has 10 edges
find the BEST_MST ( using kruskal algo) and assume BEST_MST has only 6 edges
bow there are 4 edges remaining which is not in the BEST_MST ( because their weight value is large and one of those edges will give us our 2nd_Best_MST
for each edge 'X' not present in the BEST_MST ( i.e. 4 edges left ) add that edge in out BEST_MST which will create the cycle
find the edge 'K' with the maximum weight in the cycle ( other than newly_added_edge 'X' )
remove edge 'K' temporarily which will form a new spanning tree
calculate the difference in weight and map the weight_difference with the edge 'X' .
repeat step 4 for all those 4 edges and return the spanning tree with the smallest weight difference to the BEST_MST.