公式
D - 山岳ハイキング / Mountain Hiking 解説 by admin
Qwen3-Coder-480B概要
この問題は、制限された体力 \(K\) 以内の登山道のみを使って、地点 \(1\) から地点 \(N\) へ移動する最短経路を求めるものです。各辺のコストは標高差の絶対値で決まります。
考察
この問題はグラフ上の最短経路問題として捉えることができます。各地点を頂点、通行可能な登山道をコスト付きの辺とみなします。
重要な観察
- 登山道の通行条件:標高差の絶対値が \(K\) 以下であること
- 経路のコスト:使用した登山道の標高差の総和
- 目的:地点 \(1\) から地点 \(N\) までの最短経路(コスト最小)
素朴な方法では?
例えば、幅優先探索(BFS)では「歩数」を最小にするのは得意ですが、「コストの和」を最小化することはできません。DFSなどで全探索すると、頂点数・辺数が最大 \(2 \times 10^5\) あるため、時間的に無理があります(TLE)。
解決策
重み付きグラフにおける単一始点最短経路問題を解くには、ダイクストラ法(Dijkstra’s algorithm)が有効です。ただし、通行可能な辺(標高差 \(\leq K\))のみをグラフに含めればよいです。
アルゴリズム
グラフの構築
- 各登山道について、標高差 \(|H_u - H_v|\) を計算
- それが \(K\) 以下のものだけを辺として採用(コストは標高差)
- 無向グラフなので、両方向に辺を張る
ダイクストラ法による最短距離探索
- 頂点 \(1\) からの最短距離を記録する配列
distを用意し、初期値は \(\infty\)(ただしdist[1] = 0) - 優先度付きキュー(ヒープ)を使って、現在の最小コストを持つ頂点を取り出して探索
- 頂点 \(N\) に到達したらその時点のコストが答え
- 全て探索しても到達できなければ
-1を出力
- 頂点 \(1\) からの最短距離を記録する配列
計算量
- 時間計算量: \(O((N + M) \log N)\)
- ダイクストラ法の計算量。優先度付きキューの操作が \(\log N\) かかる
- 空間計算量: \(O(N + M)\)
- グラフの隣接リストと距離配列の分
実装のポイント
- 入力を高速に読み込むために
sys.stdin.readを使用(Pythonでは重要) - ダイクストラ法のヒープには
(コスト, 頂点)のタプルを入れる - 頂点番号は1-indexedなので、配列サイズは \(N+1\) にしておく
- 経路が存在しない場合は
-1を出力することを忘れずに
## ソースコード
```python
import heapq
import sys
def main():
import sys
input = sys.stdin.read
data = input().split()
idx = 0
N = int(data[idx]); idx += 1
M = int(data[idx]); idx += 1
K = int(data[idx]); idx += 1
H = [0] * (N + 1)
for i in range(1, N + 1):
H[i] = int(data[idx]); idx += 1
# グラフ構築
graph = [[] for _ in range(N + 1)]
for _ in range(M):
u = int(data[idx]); idx += 1
v = int(data[idx]); idx += 1
cost = abs(H[u] - H[v])
if cost <= K:
graph[u].append((v, cost))
graph[v].append((u, cost))
# ダイクストラ法
dist = [float('inf')] * (N + 1)
dist[1] = 0
pq = [(0, 1)] # (距離, 頂点)
while pq:
d, u = heapq.heappop(pq)
if d > dist[u]:
continue
if u == N:
print(d)
return
for v, cost in graph[u]:
new_dist = d + cost
if new_dist < dist[v]:
dist[v] = new_dist
heapq.heappush(pq, (new_dist, v))
print(-1)
if __name__ == "__main__":
main()
この解説は qwen3-coder-480b によって生成されました。
投稿日時:
最終更新: