D - 最安経路 / Cheapest Route Editorial by admin Editorial for printing
GPT 5.2 HighOverview
This is a problem where we need to find the minimum toll (shortest distance) from city \(1\) to any airport city on a graph where the travel cost of each road is given by “the product of the populations of the two endpoint cities \(M_a \times M_b\)”.
Analysis
- Treating cities as vertices and roads as edges, the cost of moving from city \(a\) to an adjacent city \(b\) is the edge weight \(w(a,b)=M_a \times M_b\). Since roads are bidirectional, this is an undirected graph, but the cost is the same in both directions (since multiplication is commutative).
- What we want to find is “the minimum cost from city \(1\) to reach any city in the airport city set \(\{E_1,\dots,E_P\}\)” = “the shortest distance among multiple destinations from the source.”
Why a Naive Approach Fails
- Exploring all paths (e.g., enumerating all paths with DFS) causes an explosion in the number of paths, since the same cities and roads can be visited repeatedly.
- BFS only guarantees shortest distances when all edge weights are equal. In this problem, \(M_a \times M_b\) can differ for each edge, so BFS would give incorrect answers.
Solution Strategy
- Since all edge weights are non-negative (\(M_i \ge 1\), so the product is also positive), we can find shortest distances using Dijkstra’s algorithm.
- Even when there are multiple destinations, by leveraging Dijkstra’s property of confirming vertices in order of shortest distance, the answer is determined the moment we first confirm an airport city (no cheaper airport can exist).
Example: Even if there are multiple airports, since the distances extracted from the priority queue are monotonically non-decreasing, the “first airport extracted” has the minimum distance among all airports.
Algorithm
- Manage whether each city is an airport using an array
is_airport. - If city \(1\) is an airport, no travel is needed and the answer is \(0\).
- Prepare a distance array
distwithdist[1]=0and all others set to \(\infty\). - Insert
(0, 1)into a priority queue (min-heap) and start Dijkstra’s algorithm. - Extract
(d, u)from the heap.- If the extracted
ddiffers fromdist[u], it is outdated information, so skip it. - If
uis an airport city,dis the minimum toll, so output it and terminate.
- If the extracted
- For all adjacent vertices
vofu, compute the transition cost by adding \(M_u \times M_v\): $\( nd = d + M_u \times M_v \)$ and relax: ifnd < dist[v], update and insert into the heap. - Since it is always possible to reach some airport, the algorithm will terminate at some point.
Complexity
- Time complexity: \(O((N+K)\log N)\)
(Dijkstra’s algorithm: each edge is relaxed at most \(2K\) times, with \(\log N\) per heap operation) - Space complexity: \(O(N+K)\)
(adjacency list, distance array, airport flags, heap)
Implementation Notes
“Terminate immediately upon reaching an airport” is crucial. Since Dijkstra’s algorithm confirms vertices in order of minimum distance, the first confirmed airport gives the answer.
In Python, since the input can be large, we use
sys.stdin.buffer.read()for fast input.The adjacency list is also implemented in array format (
head/to/nxt, C-style) to run efficiently even for \(N,K \le 2\times 10^5\).Since the maximum distance can become very large (products are added many times along a path), we use a sufficiently large value like
INF=10**30.Source Code
import sys
import heapq
def main():
data = sys.stdin.buffer.read()
ndata = len(data)
ptr = 0
def next_int():
nonlocal ptr
while ptr < ndata and data[ptr] <= 32:
ptr += 1
sign = 1
if ptr < ndata and data[ptr] == 45:
sign = -1
ptr += 1
num = 0
while ptr < ndata:
c = data[ptr]
if c <= 32:
break
num = num * 10 + (c - 48)
ptr += 1
return num * sign
N = next_int()
K = next_int()
P = next_int()
M = [0] * (N + 1)
for i in range(1, N + 1):
M[i] = next_int()
head = [-1] * (N + 1)
to = [0] * (2 * K)
nxt = [0] * (2 * K)
ei = 0
for _ in range(K):
u = next_int()
v = next_int()
to[ei] = v
nxt[ei] = head[u]
head[u] = ei
ei += 1
to[ei] = u
nxt[ei] = head[v]
head[v] = ei
ei += 1
is_airport = [False] * (N + 1)
for _ in range(P):
e = next_int()
is_airport[e] = True
if is_airport[1]:
print(0)
return
INF = 10**30
dist = [INF] * (N + 1)
dist[1] = 0
hq = [(0, 1)]
while hq:
d, u = heapq.heappop(hq)
if d != dist[u]:
continue
if is_airport[u]:
print(d)
return
mu = M[u]
e = head[u]
while e != -1:
v = to[e]
nd = d + mu * M[v]
if nd < dist[v]:
dist[v] = nd
heapq.heappush(hq, (nd, v))
e = nxt[e]
if __name__ == "__main__":
main()
This editorial was generated by gpt-5.2-high.
posted:
last update: