Problem Description
Given an undirected, weighted, and connected graph with n nodes and a list of edges (some with unknown weight, i.e. -1), assign a positive integer (in [1, 2 * 10^9]) to every edge whose weight is -1 so that the shortest distance between a specified source and destination becomes exactly target. You are not allowed to change edges that already have a positive weight. If one such modification is possible, return an array of all edges with the modified weights (order may change); otherwise, return an empty array.
Key Insights
- First, use Dijkstra’s algorithm twice:
- Once setting all unknown (-1) weights to 1 to get the minimum possible distance.
- Once setting all unknown weights to a very large number (2*10^9) to get the maximum possible distance.
- If the target is not between these two computed distances, a solution is impossible.
- Compute a helper array (distances from each node to the destination) using Dijkstra’s reversed graph where unknown weights are 1. This will be used to “reserve” the necessary slack for adjustment.
- Do a “forward” Dijkstra from the source. When relaxing an edge with unknown weight, determine the required weight = target - (current distance from source) - (precomputed distance from neighbor to destination). This adjustment “forces” the shortest path to add up to target.
- Finally, assign 1 to any remaining unknown edges that were not used (or didn’t require adjustment) and return all edges.
Space and Time Complexity
Time Complexity: O(m log n) where m is the number of edges and n is the number of nodes (Dijkstra’s algorithm is run multiple times). Space Complexity: O(n + m) for storing the graph and auxiliary arrays.
Solution
We first run Dijkstra’s algorithm from the destination in the reverse graph with all unknown edges set to a weight of 1. This gives us, for every node, the minimum distance to the destination ignoring modifications. Then, we run a forward Dijkstra from the source. For each edge which originally had weight -1, we calculate the would–be needed weight that makes current_distance + (new_weight) + (distance from neighbor to destination) exactly equal to target. If the computed weight is below 1, we use 1; if above 210^9, we use 210^9. This update “fixes” that unknown edge when it is used in the shortest path so that the overall distance is forced to target. Finally, we verify that the distance from source to destination in our modified graph is exactly target. If so, we update all remaining -1 edges to 1 and output the modified edge list; if not, we return an empty array.
Key data structures:
- An adjacency list (graph) representation.
- A min heap (priority queue) for Dijkstra.
- Two distance arrays (one from the destination; one from the source with modifications).
The “gotcha” is ensuring that the computed new weight for an edge exactly “absorbs” the slack needed to reach the target distance while also keeping the modification valid (in [1, 2*10^9]).