Official

D - 最安経路 / Cheapest Route Editorial by admin

Claude 4.6 Opus (Thinking)

Overview

This is a problem of finding the shortest path from city \(1\) to any city with an airport, using Dijkstra’s algorithm. The cost of an edge is determined by the product of the populations of the two cities at its endpoints.

Analysis

Rephrasing the Problem

This problem can be reduced to a shortest path problem on a weighted graph.

  • Vertices: \(N\) cities
  • Edges: \(K\) roads. The weight of the edge connecting city \(a\) and city \(b\) is \(M_a \times M_b\)
  • Source: City \(1\)
  • Goal: Any one of the cities with airports \(E_1, E_2, \dots, E_P\)

In other words, this is a single-source shortest path problem: “reach any one of the multiple goal candidates from city \(1\) with minimum cost.”

Why Dijkstra’s Algorithm Works

The weight of an edge is \(M_a \times M_b\), and since \(M_i \geq 1\), all edge weights are non-negative. Therefore, Dijkstra’s algorithm works correctly.

Comparison with a Naive Approach

BFS (Breadth-First Search) can only find shortest paths when all edge weights are equal. In this problem, edge weights differ from edge to edge, so BFS cannot produce the correct answer (it will result in WA). Dijkstra’s algorithm must be used.

Handling Multiple Goals

In Dijkstra’s algorithm, vertices are finalized in order of increasing distance. Therefore, when a city with an airport is first extracted from the heap, that distance is the “minimum cost to any airport.” There is no need to compute distances to all airports and then compare them — it is efficient to terminate as soon as the first one is found.

Algorithm

  1. Graph Construction: For each road, compute the edge weight \(M_{U_k} \times M_{V_k}\) and store it in an adjacency list.
  2. Special Case Handling: If city \(1\) itself has an airport, the answer is \(0\).
  3. Running Dijkstra’s Algorithm:
    • Initialize the distance of city \(1\) to \(0\) and insert it into a priority queue (min-heap).
    • Extract the city \(u\) with the minimum distance from the heap.
    • If \(u\) is a city with an airport, output its distance and terminate.
    • Otherwise, for each neighboring city \(v\) of \(u\), if \(dist[u] + M_u \times M_v\) improves \(dist[v]\), add it to the heap.
  4. The distance at the moment an airport city is first extracted from the heap is the answer.

Concrete Example

For example, suppose there are 3 cities, roads \((1,2)\) and \((2,3)\), populations \(M = [-, 3, 2, 5]\) (1-indexed), and the airport is at city \(3\):

  • Weight of edge \((1,2)\): \(3 \times 2 = 6\)
  • Weight of edge \((2,3)\): \(2 \times 5 = 10\)
  • Cost of city \(1 \to 2 \to 3\): \(6 + 10 = 16\)

Complexity

  • Time complexity: \(O((N + K) \log N)\) (standard complexity of Dijkstra’s algorithm)
  • Space complexity: \(O(N + K)\) (adjacency list and distance array)

Implementation Tips

  • Early Termination: If the city extracted from the heap has an airport, immediately output the answer and terminate. This avoids exploring all vertices.

  • Avoiding Redundant Processing: If the distance \(d\) extracted from the heap is greater than the already recorded \(dist[u]\), skip it (if d > dist[u]: continue). This is a standard technique in Dijkstra’s algorithm.

  • Fast Input: Using sys.stdin.buffer.read() to read all input at once makes it easier to avoid TLE in Python.

  • Airport Set Management: Storing cities with airports in a set allows \(O(1)\) lookup to check whether a given city has an airport.

    Source Code

import heapq
import sys

def main():
    input_data = sys.stdin.buffer.read().split()
    idx = 0
    N = int(input_data[idx]); idx += 1
    K = int(input_data[idx]); idx += 1
    P = int(input_data[idx]); idx += 1
    
    M = [0] * (N + 1)
    for i in range(1, N + 1):
        M[i] = int(input_data[idx]); idx += 1
    
    adj = [[] for _ in range(N + 1)]
    for _ in range(K):
        u = int(input_data[idx]); idx += 1
        v = int(input_data[idx]); idx += 1
        cost = M[u] * M[v]
        adj[u].append((v, cost))
        adj[v].append((u, cost))
    
    airports = set()
    for _ in range(P):
        e = int(input_data[idx]); idx += 1
        airports.add(e)
    
    if 1 in airports:
        print(0)
        return
    
    INF = float('inf')
    dist = [INF] * (N + 1)
    dist[1] = 0
    heap = [(0, 1)]
    
    while heap:
        d, u = heapq.heappop(heap)
        if d > dist[u]:
            continue
        if u in airports:
            print(d)
            return
        for v, w in adj[u]:
            nd = d + w
            if nd < dist[v]:
                dist[v] = nd
                heapq.heappush(heap, (nd, v))
    
    # Should not reach here given the problem guarantees
    ans = INF
    for e in airports:
        ans = min(ans, dist[e])
    print(ans)

main()

This editorial was generated by claude4.6opus-thinking.