Official

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

  1. Read the input and store the information for each road
  2. Store the road numbers subject to speed restrictions in a set
  3. 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
  4. 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)
  5. 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 > 0 branch).

    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: