公式

D - 往復配達 / Round-Trip Delivery 解説 by admin

Gemini 3.0 Flash

Overview

This problem asks us to find the shortest round-trip path in a weighted undirected graph, starting from base \(1\), passing through base \(T\), and returning to base \(1\).

Analysis

When solving this shortest path problem, we focus on the following important properties.

  1. Independence of the outbound and return trips Takahashi’s journey can be divided into an outbound trip “base \(1 \to T\)” and a return trip “base \(T \to 1\)”. To minimize the total time, we simply need to achieve the shortest time for each of the outbound and return trips independently.

  2. Symmetry of undirected graphs The roads in this problem form an undirected graph (bidirectional traversal with the same cost). In an undirected graph, “the shortest distance from point \(A\) to point \(B\)” and “the shortest distance from point \(B\) to point \(A\)” are always equal. Therefore, the minimum total time we seek is: $\((\text{shortest distance from base } 1 \text{ to } T) \times 2\)$

  3. Shortest path search Since the number of bases \(N\) can be up to \(10^5\) and the number of roads \(M\) can be up to \(2 \times 10^5\), an efficient shortest path algorithm is required. Since all edge weights are positive, Dijkstra’s algorithm is the optimal choice.

If Dijkstra’s algorithm results in the distance to base \(T\) being infinity (unreachable), then a round trip is also impossible, so we output -1.

Algorithm

We solve this using Dijkstra’s algorithm (with a priority queue).

  1. Store the graph in adjacency list format.
  2. Initialize the distance array dist to infinity, and set dist[1] = 0 for the starting point.
  3. Add (distance 0, base 1) to the priority queue.
  4. Repeat the following operations until the queue is empty:
    • Extract the base \(u\) with the shortest distance.
    • If it has already been finalized with a shorter distance, skip it.
    • For each base \(v\) adjacent to base \(u\), if going through base \(u\) results in a shorter arrival time, update dist[v] and add it to the queue.
    • (As an optimization, the search can be terminated as soon as the shortest distance to base \(T\) is finalized.)
  5. If dist[T] has been updated, output dist[T] * 2; otherwise, output -1.

Complexity

  • Time complexity: \(O(M \log N)\) In Dijkstra’s algorithm, each edge is examined at most once, and each priority queue operation takes \(O(\log N)\).
  • Space complexity: \(O(N + M)\) This is the memory required to store the adjacency list and the distance array.

Implementation Notes

  • Fast I/O: Since \(N\) and \(M\) can be large, in Python you can reduce execution time by reading all input at once using sys.stdin.read().split() or similar methods.

  • Unreachability check: Initialize the distance array with a very large value (such as float('inf')), and if the final value remains unchanged, determine that the destination is unreachable.

  • Overflow: The answer can be on the order of \(2 \times 10^{14}\), but since Python automatically handles arbitrary-precision integers, no special measures are needed. In other languages (such as C++), you need to use the long long type.

    Source Code

import heapq
import sys

def solve():
    # 標準入力から全てのデータを読み込み、空白で分割してリストにする
    # 大規模な入力に対して高速に動作させるための手法
    input_data = sys.stdin.read().split()
    if not input_data:
        return
    
    it = iter(input_data)
    
    # N: 拠点の数, M: 道路の数, T: 訪問すべき拠点
    try:
        N = int(next(it))
        M = int(next(it))
        T = int(next(it))
    except StopIteration:
        return
    
    # 隣接リストの構築
    adj = [[] for _ in range(N + 1)]
    for _ in range(M):
        try:
            u = int(next(it))
            v = int(next(it))
            w = int(next(it))
            # 無向グラフなので両方向に追加
            adj[u].append((v, w))
            adj[v].append((u, w))
        except StopIteration:
            break
            
    # ダイクストラ法による最短経路探索
    # dist[i] は拠点1から拠点iまでの最短距離を保持する
    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
        
        # 目的の拠点 T に到達した時点で最短距離が確定するため終了可能
        if u == T:
            break
            
        # 隣接する拠点を探索
        for v, w in adj[u]:
            new_dist = d + w
            if new_dist < dist[v]:
                dist[v] = new_dist
                heapq.heappush(pq, (new_dist, v))
                
    # 拠点 T に到達できない場合
    if dist[T] == inf:
        print("-1")
    else:
        # 往復の最小時間は、行き(1からT)と帰り(Tから1)の最短距離の合計
        # 無向グラフにおいて最短経路は往路・復路で等しいため、2倍の値を出力する
        print(dist[T] * 2)

if __name__ == "__main__":
    solve()

This editorial was generated by gemini-3-flash-preview.

投稿日時:
最終更新: