公式

C - 島巡りの冒険 / Island Hopping Adventure 解説 by admin

Gemini 3.0 Flash (Thinking)

Overview

This problem asks us to find the shortest path (minimum number of moves) from a starting island \(S\) to a goal island \(T\) in a graph where the \(N\) islands are treated as vertices and edges connect pairs of islands within distance \(D\) of each other.

Analysis

Reformulation as a Graph Problem

By treating each island as a “vertex” and each pair of reachable islands as an “edge,” this problem reduces to a classic single-source shortest path problem. - Number of vertices \(N\): up to 1500 - Edge condition: the Euclidean distance between two islands satisfies \(\sqrt{(X_i - X_j)^2 + (Y_i - Y_j)^2} \leq D\)

Optimization of Distance Computation

Computing the Euclidean distance involves a square root (sqrt), which can introduce floating-point errors when using floating-point numbers. By squaring both sides of the inequality, we can perform the comparison using only integer arithmetic: $\((X_i - X_j)^2 + (Y_i - Y_j)^2 \leq D^2\)$ This technique allows us to make exact comparisons without worrying about precision errors.

Shortest Path Algorithm

Since we are finding the shortest path in an unweighted graph (all edge lengths are 1), Breadth-First Search (BFS) is the optimal approach. With \(N = 1500\), precomputing distances between all pairs of islands to build an adjacency list (\(O(N^2)\)) would be fast enough. However, in this implementation, we efficiently check only “unvisited islands” during the search, eliminating unnecessary computations.

Algorithm

  1. Initialization:
    • Initialize an array dist that stores the shortest distance to each island with \(-1\) (unvisited), and set dist[S] = 0 for the starting island.
    • Create a list unvisited of all unvisited islands.
    • Add the starting island \(S\) to the search queue queue.
  2. Breadth-First Search (BFS):
    • Dequeue an island \(u\) from the queue.
    • For each island \(v\) in the unvisited list, check whether the distance from island \(u\) is at most \(D\).
    • If the distance is at most \(D\):
      • Update dist[v] = dist[u] + 1.
      • If island \(v\) is the destination \(T\), output dist[v] at that point and terminate.
      • Add island \(v\) to the queue and remove it from unvisited.
  3. Termination:
    • If the queue becomes empty without reaching \(T\), output \(-1\).

Complexity

  • Time Complexity: \(O(N^2)\)
    • Each island enters the queue at most once.
    • At each step, we scan the unvisited list. Since the distance check for any pair of islands is performed at most once, the overall complexity is \(O(N^2)\). When \(N=1500\), \(N^2 = 2.25 \times 10^6\), which comfortably fits within the time limit.
  • Space Complexity: \(O(N)\)
    • Storing the coordinate data, distance array, queue, and unvisited list requires \(O(N)\) memory.

Implementation Notes

  • Fast I/O: Since \(N\) is relatively large, reading all input at once using methods like sys.stdin.read().split() can reduce execution time.

  • Conversion to 0-indexed: The problem numbers islands from 1 to \(N\), but handling them as 0 to \(N-1\) in the program makes array index operations smoother.

  • Managing the Unvisited List: By updating the unvisited list to avoid re-checking already visited islands, we improve the efficiency of the search.

    Source Code

import sys
from collections import deque

def solve():
    # すべての入力を一括で読み込みます
    input_data = sys.stdin.read().split()
    if not input_data:
        return
    
    # 基本パラメータのパース
    # N: 島の数, D: 一度に移動できる最大距離, S: 出発する島, T: 目的の島
    N = int(input_data[0])
    D = int(input_data[1])
    S = int(input_data[2]) - 1  # 0-indexedに変換
    T = int(input_data[3]) - 1  # 0-indexedに変換
    
    # 各島の座標を読み込みます
    X = [0] * N
    Y = [0] * N
    for i in range(N):
        X[i] = int(input_data[4 + 2*i])
        Y[i] = int(input_data[5 + 2*i])
        
    # ユークリッド距離の比較を高速化するため、距離の2乗を計算しておきます
    D2 = D * D
    
    # 幅優先探索 (BFS) を用いて最短移動回数を求めます
    # dist[i] は島 S から島 i までの最小移動回数を保持します
    dist = [-1] * N
    dist[S] = 0
    queue = deque([S])
    
    # まだ訪れていない島のリストを保持します
    # これにより、探索済みの島を何度もチェックするのを避けます
    unvisited = [i for i in range(N) if i != S]
    
    while queue:
        u = queue.popleft()
        ux, uy = X[u], Y[u]
        
        # 今回のステップで訪問できなかった島を保持するための新しいリスト
        next_unvisited = []
        for v in unvisited:
            dx = ux - X[v]
            dy = uy - Y[v]
            # 浮動小数点の誤差を避けるため、2乗の状態で比較を行います
            if dx * dx + dy * dy <= D2:
                dist[v] = dist[u] + 1
                # 目的地に到達した場合、即座に結果を出力して終了します
                if v == T:
                    print(dist[v])
                    return
                queue.append(v)
            else:
                # 到達できなかった島は次回の探索候補として残します
                next_unvisited.append(v)
        
        # 未訪問リストを更新
        unvisited = next_unvisited
        
    # キューが空になっても目的地 T に到達できなかった場合
    print("-1")

if __name__ == '__main__':
    solve()

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

投稿日時:
最終更新: