公式

D - 山岳ハイキング / Mountain Hiking 解説 by admin

Claude 4.6 Opus (Thinking)

Overview

This problem asks you to find the shortest path (minimum total fatigue) from point \(1\) to point \(N\) after excluding trails whose elevation difference exceeds stamina \(K\). It is a typical constrained shortest path problem and can be solved with Dijkstra’s algorithm.

Analysis

Key Observations

  1. Some edges are unusable: If the elevation difference \(|H_{U_j} - H_{V_j}|\) of a trail exceeds \(K\), that trail cannot be traversed at all. In other words, we can simply remove that edge from the graph.

  2. Edge weights are non-negative: Since fatigue is the absolute value of the elevation difference, it is always \(0\) or greater. This is very important because Dijkstra’s algorithm can be used when edge weights are non-negative.

  3. Reduction to a shortest path problem: This is equivalent to finding the shortest distance from point \(1\) to point \(N\) in a graph composed only of passable edges.

Comparison with Naive Approaches

  • BFS (Breadth-First Search): BFS would suffice if all edge weights were the same (unweighted), but since edge weights differ in this problem, BFS cannot correctly determine the shortest distance.
  • Bellman-Ford algorithm: This can correctly find the answer, but with a time complexity of \(O(NM)\), it is too slow when \(N, M\) can be up to \(2 \times 10^5\).
  • Dijkstra’s algorithm: Since edge weights are non-negative, it is applicable, and using a priority queue, it efficiently solves the problem in \(O((N + M) \log N)\).

Algorithm

  1. Graph construction: For each trail, compute the elevation difference \(|H_{U_j} - H_{V_j}|\). If it is at most \(K\), add it to the adjacency list. Edges exceeding \(K\) are ignored.

  2. Running Dijkstra’s algorithm:

    • Initialize the distance for point \(1\) to \(0\) and all others to \(\infty\).
    • Insert \((0, 1)\) (distance, point) into a priority queue (min-heap).
    • Extract the point with the minimum distance from the queue and update (relax) the distances to adjacent points.
    • When point \(N\) is extracted, its distance is the answer.
  3. Unreachability check: If the queue becomes empty without reaching point \(N\), output -1.

Concrete Example

For example, with \(N=3, M=2, K=5\), elevations \(H = [10, 13, 20]\), and edges \((1,2)\) and \((2,3)\): - Edge \((1,2)\): elevation difference \(|10-13| = 3 \leq 5\) → passable, fatigue \(3\) - Edge \((2,3)\): elevation difference \(|13-20| = 7 > 5\) → impassable

Since edge \((2,3)\) cannot be used, point \(3\) is unreachable from point \(1\), and the answer is -1.

Complexity

  • Time complexity: \(O((N + M) \log N)\) (standard complexity of Dijkstra’s algorithm)
  • Space complexity: \(O(N + M)\) (for storing the adjacency list and distance array)

Implementation Notes

  • Filter edges during graph construction: By excluding edges exceeding \(K\) at the stage of building the adjacency list, there is no need to check the condition during Dijkstra’s exploration, making the code cleaner.

  • Early termination: Since the shortest distance is finalized when point \(N\) is extracted from the queue, you can immediately output the answer and terminate. This avoids unnecessary exploration.

  • Fast input: By using sys.stdin.buffer.read() to read all input at once, input is less likely to become a bottleneck even in Python.

    Source Code

import heapq
import sys

def main():
    input_data = sys.stdin.buffer.read().split()
    idx = 0
    N = int(input_data[idx]); idx += 1
    M = int(input_data[idx]); idx += 1
    K = int(input_data[idx]); idx += 1
    
    H = [0] * (N + 1)
    for i in range(1, N + 1):
        H[i] = int(input_data[idx]); idx += 1
    
    adj = [[] for _ in range(N + 1)]
    for _ in range(M):
        u = int(input_data[idx]); idx += 1
        v = int(input_data[idx]); idx += 1
        diff = abs(H[u] - H[v])
        if diff <= K:
            adj[u].append((v, diff))
            adj[v].append((u, diff))
    
    # Dijkstra from node 1 to node N
    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
        if u == N:
            print(d)
            return
        for v, w in adj[u]:
            nd = d + w
            if nd < dist[v]:
                dist[v] = nd
                heapq.heappush(pq, (nd, v))
    
    print(-1)

main()

This editorial was generated by claude4.6opus-thinking.

投稿日時:
最終更新: