Editorial for CCC '23 S4 - Minimum Cost Roads
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Subtask 1
This subtask can be solved by running an MST (Minimum Spanning Tree) algorithm that only considers the cost of each edge. Note that we may have multiple components, so our final answer will be the sum of costs of the MST of each component. Luckily, an algorithm like Kruskal's handles this problem without any additional complexity.
Subtask 2
The constraints of this subtask allow us to focus on an invariant that is very useful in the long run. Consider a single edge . We get the following cases:
- If is the unique shortest path from to , we definitely want to take ;
- If there exists a path from to with length , we definitely don't want to take ;
If there exists another path from to with length (but no paths that are shorter), we still don't want to take . However, this time the proof is much more complex:
Suppose is a path from to consisting of edges such that
Now, suppose that , is the unique shortest path between its endpoints and . If this is not the case for some , then we can find another path from to with length exactly and replace with that path (if that path had length then we would have a path from to with length , which is a contradiction). Observe that this process can only be repeated a finite number of times.
In the end, we have a path from to that has length , does not take the edge , and every edge in that path is the unique shortest path between its endpoints. We'll call the edges on this path .
Now consider some optimal answer that contains the edge . Clearly, must be in the answer. However, this means that we can remove as any time we need to traverse from to , we can take the edges instead. This violates the optimality of the answer and is thus a contradiction.
This results in a very simple solution for this subtask: we loop over every edge and check whether it's the unique shortest path between and . One way to do this is to first run Dijkstra's algorithm times to find the shortest path between every pair of nodes (and store it in a 2-D array ). Then, for each edge we check if
Remark: Notice that we don't even care about costs at all! In fact, the original problem didn't have costs (), but we thought it was an interesting extension :)
Subtask 3
Unfortunately, we lose the guarantees that allow our solution from subtask 2 to work. Fortunately, we can restore these guarantees with some clever reductions.
First, let's look at the graph formed by all of the -length edges. If any pair of nodes are connected in this graph, then our answer must contain a path of length between and . Thus, we must choose a subset of the -length edges that has the same connectivity properties as the original graph (i.e. if are connected by -length edges in the original graph, then they must be connected by -length edges in our answer). Trying to do so while also minimizing cost is analogous to finding the minimum spanning forest of the graph, which is the same as our solution in subtask 1.
Unfortunately, the -length edges are still part of our graph. In order to remove them for good, we must make the following observation: we can treat each component in our spanning forest as a single node as we're able to travel between any two nodes in that component with a path of length . This motivates us to compress our initial graph by these components to remove all -length edges.
Note: Be careful, the compressed graph may also contain self-edges so make sure to ignore them.
Next, to remove multiedges notice that we only ever want at most one edge between any pair of nodes. Thus, we take the one with lowest length, breaking ties by cost.
Finally, we run our solution from subtask 2 and sum the answer we obtained from that solution with the one from computing the minimum spanning forest.
Alternative Solution
There is also an alternative solution much closer to Kruskal's algorithm for computing MST: we loop over the edges in order of length, breaking ties by cost and adding it to the graph if it improves the shortest path between its endpoints. This solution also has the added benefit of not worrying about -length edges or multi-edges separately.
Comments