D - 届け物 / Delivery Editorial by admin
gpt-5.3-codex概要
「\(S \rightarrow G \rightarrow T\) の順で移動する最短時間」を求める問題です。
重み付き無向グラフなので、最短経路計算にダイクストラ法を使うのが基本になります。
考察
重要なポイントは、経由点 \(G\) が必須であることです。
この条件がある最短経路は、次の2つに分けて考えられます。
- \(S\) から \(G\) までの最短距離
- \(G\) から \(T\) までの最短距離
全体の最短時間は、この和 [ \text{dist}(S,G) + \text{dist}(G,T) ] になります。
なぜこれでよいかというと、経路全体が \(S \to \cdots \to G \to \cdots \to T\) という形なら、前半と後半は独立に最短化できるためです。
もし前半が最短でなければ、より短い前半に置き換えて全体を短くできてしまい、最短であることに矛盾します。後半も同様です。
素朴に「\(S\) から全経路探索して \(G\) を通って \(T\) に行く最短」をやろうとすると、経路数が膨大になり現実的ではありません(指数的に増える可能性)。
また、重み付きグラフなので BFS では正しい最短距離を出せません(BFS は辺重みがすべて同じときのみ有効)。
そこで、非負重みの最短経路に強いダイクストラ法を使います。
必要なのは \(S\) 始点と \(G\) 始点の2回だけです。
アルゴリズム
- 隣接リストで無向グラフを構築する。
- ダイクストラ法を \(S\) から実行し、
distSを得る(各頂点への最短距離)。 - ダイクストラ法を \(G\) から実行し、
distGを得る。 distS[G]またはdistG[T]が到達不能(INF)の場合は-1。- そうでなければ
distS[G] + distG[T]を出力。
コード中の if d != dist[v]: continue は、優先度付きキューに残っている古い(不要な)情報を捨てるための定番テクニックです。
計算量
- 時間計算量: \(O((N+M)\log N)\) を2回実行するので、定数倍を除いて \(O((N+M)\log N)\)
- 空間計算量: \(O(N+M)\)(グラフ + 距離配列 + 優先度付きキュー)
実装のポイント
距離は最大で大きくなるため、
INF = 10**30のように十分大きい値を使う。頂点番号が \(1\) 始まりなので、配列サイズを
N+1にする。到達不能判定を忘れずに行う(
distS[G] >= INFまたはdistG[T] >= INF)。ソースコード
import sys
import heapq
def dijkstra(start, graph, n):
INF = 10**30
dist = [INF] * (n + 1)
dist[start] = 0
pq = [(0, start)]
while pq:
d, v = heapq.heappop(pq)
if d != dist[v]:
continue
for to, w in graph[v]:
nd = d + w
if nd < dist[to]:
dist[to] = nd
heapq.heappush(pq, (nd, to))
return dist
def main():
input = sys.stdin.readline
N, M, S, G, T = map(int, input().split())
graph = [[] for _ in range(N + 1)]
for _ in range(M):
u, v, c = map(int, input().split())
graph[u].append((v, c))
graph[v].append((u, c))
distS = dijkstra(S, graph, N)
distG = dijkstra(G, graph, N)
INF = 10**30
if distS[G] >= INF or distG[T] >= INF:
print(-1)
else:
print(distS[G] + distG[T])
if __name__ == "__main__":
main()
この解説は gpt-5.3-codex によって生成されました。
posted:
last update: