公式

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


この問題は BFS (幅優先探索)により解くことができます。 島 \(S\) のみをキューに入れた状態からスタートし、キューの先頭から島を取り出しては、各島がそこから直接到達可能か調べ、到達可能かつ未踏の島であれば移動回数を記録してキューに追加します。

各島から各島へ到達可能であるかを高々 \(1\) 回調べるため、計算量は \(O(N^2)\) になります。

なお、距離の計算を問題文の数式の通りに計算し、浮動小数点数を用いて比較を行うと、誤差の影響で誤判定することがあります。例えば \(x=958043599\) のとき sqrt(x * x + 1) <= x は True となります。
両辺を 2 乗することで、整数の範囲で比較を行うことができ、誤差の影響を避けることができます。

実装例 (C++)

#include<bits/stdc++.h>
using namespace std;

int main(){
  int n, s, t;
  long long d;
  cin >> n >> d >> s >> t;
  s--, t--;
  vector<pair<long long, long long>>xy(n);
  for(int i=0; i<n; i++) cin >> xy[i].first >> xy[i].second;

  auto is_reachable=[&](int i, int j){
    auto [xi, yi] = xy[i];
    auto [xj, yj] = xy[j];
    return (xi - xj) * (xi - xj) + (yi - yj) * (yi - yj) <= d * d;
  };

  int INF = 1e9;
  vector<int>dist(n, INF);
  dist[s] = 0;
  queue<int>q;
  q.push(s);
  while(q.size() > 0){
    int v = q.front();
    q.pop();
    for(int vv=0; vv<n; vv++){
      if(is_reachable(v, vv) && dist[vv] == INF){
        dist[vv] = dist[v] + 1;
        q.push(vv);
      }
    }
  }
  
  if(dist[t] == INF){
   cout << -1 << endl;
  }else{
    cout << dist[t] << endl;
  }
}

実装例 (Python)

N, D, S, T = map(int, input().split())
S -= 1
T -= 1
XY = []
for _ in range(N):
  X, Y = map(int,input().split())
  XY.append((X, Y))

def is_reachable(i, j):
  Xi, Yi = XY[i]
  Xj, Yj = XY[j]
  return (Xi - Xj) ** 2 + (Yi - Yj) ** 2 <= D ** 2

INF = 10**18
dist = [INF]*N
dist[S] = 0
q = [S]
for v in q:
  for vv in range(N):
    if is_reachable(v, vv) and dist[vv] == INF:
      dist[vv] = dist[v]+1
      q.append(vv)

if dist[T] == INF:
  print(-1)
else:
  print(dist[T])

投稿日時:
最終更新: