D - 配達ルートの最適化 / Optimizing Delivery Routes Editorial by admin
Claude 4.6 Opus (Thinking)Overview
This problem asks you to find the shortest path from point \(1\) to point \(N\) after doubling the travel time of roads with speed restrictions. It is a typical weighted graph shortest path problem that can be solved using Dijkstra’s algorithm.
Analysis
Problem Summary
- A graph consisting of \(N\) points and \(M\) bidirectional roads is given
- \(K\) roads have speed restrictions, and their travel times become 2 times the normal amount
- Find the shortest time from point \(1\) to point \(N\)
Key Insight
In this problem, the speed restrictions only change the edge weights — the graph structure itself does not change. In other words, we just need to set the edge weights appropriately and then solve a standard shortest path problem.
Specifically, we set the weight of road \(i\) as follows:
- If road \(i\) is subject to speed restrictions (\(i \in \{C_1, C_2, \ldots, C_K\}\)), the weight is \(2W_i\)
- Otherwise, the weight is \(W_i\)
Why Dijkstra’s Algorithm?
Since all edge weights are positive (\(W_i \geq 1\), so \(2W_i\) is also positive), Dijkstra’s algorithm is applicable. BFS cannot be used because it is designed for unweighted graphs. The Bellman–Ford algorithm would also yield correct results, but its time complexity is \(O(NM)\), which may not be fast enough when \(N, M\) are up to \(2 \times 10^5\).
Algorithm
- Read the input and store the information for each road
- Store the road numbers subject to speed restrictions in a set
- Build an adjacency list. For each road, add an edge with weight \(2W_i\) if it is subject to speed restrictions, or weight \(W_i\) otherwise
- Run Dijkstra’s algorithm to find the shortest distance from point \(1\) to each point
- Use a priority queue (min-heap) to finalize vertices in order of increasing distance
- Early termination is possible when point \(N\) is reached (optimization)
- Output the shortest distance to point \(N\). If it is unreachable, output \(-1\)
Concrete Example
For example, suppose \(N=3, M=3\) with the following roads: - Road 1: Points 1–2, travel time \(3\) - Road 2: Points 2–3, travel time \(5\) - Road 3: Points 1–3, travel time \(10\)
If road 3 is subject to speed restrictions (\(K=1, C_1=3\)), the travel time for road 3 becomes \(20\). Then the route point 1 → point 2 → point 3 (travel time \(3+5=8\)) is the shortest.
Complexity
- Time complexity: \(O((N + M) \log N)\)
- This is the standard complexity of Dijkstra’s algorithm. For each edge, at most one heap operation (\(O(\log N)\)) is performed.
- Space complexity: \(O(N + M)\)
- For the adjacency list, distance array, and priority queue.
Implementation Notes
Fast determination of speed restrictions: By storing the road numbers subject to speed restrictions in a
set, we can check membership in \(O(1)\). Performing a linear search through a list (\(O(K)\)) each time would be slow.Fast input reading: Since \(N, M\) can be large, in Python we use
sys.stdin.buffer.read()to read all input at once, speeding up input processing.Early termination: When point \(N\) is extracted from the heap in Dijkstra’s algorithm, its distance is guaranteed to be the shortest, so we can immediately output the answer and terminate.
Case \(K = 0\): When there are no roads subject to speed restrictions, note that the last line of input does not exist (handled in the code with an
if K > 0branch).Source Code
import heapq
import sys
def main():
input_data = sys.stdin.buffer.read().split()
idx = 0
N = int(input_data[idx]); idx += 1
M = int(input_data[idx]); idx += 1
K = int(input_data[idx]); idx += 1
edges = []
for i in range(M):
U = int(input_data[idx]); idx += 1
V = int(input_data[idx]); idx += 1
W = int(input_data[idx]); idx += 1
edges.append((U, V, W))
restricted = set()
if K > 0:
for j in range(K):
C = int(input_data[idx]); idx += 1
restricted.add(C)
# Build adjacency list
adj = [[] for _ in range(N + 1)]
for i in range(M):
U, V, W = edges[i]
road_id = i + 1
if road_id in restricted:
w = 2 * W
else:
w = W
adj[U].append((V, w))
adj[V].append((U, w))
# Dijkstra
INF = float('inf')
dist = [INF] * (N + 1)
dist[1] = 0
pq = [(0, 1)]
while pq:
d, u = heapq.heappop(pq)
if d > dist[u]:
continue
if u == N:
print(d)
return
for v, w in adj[u]:
nd = d + w
if nd < dist[v]:
dist[v] = nd
heapq.heappush(pq, (nd, v))
print(-1 if dist[N] == INF else dist[N])
main()
This editorial was generated by claude4.6opus-thinking.
posted:
last update: