D - 登山ルートの選択 / Selection of a Mountain Climbing Route 解説 by admin
Claude 4.6 Opus (Thinking)Overview
This is a problem where we want to travel from point \(1\) to point \(N\) using a route with at most \(K\) waypoints, minimizing the maximum elevation along the route. We solve “minimizing the maximum value” using binary search + BFS.
Analysis
Key Insight: Minimizing the maximum is well-suited for binary search
Directly solving the optimization problem “minimize the highest elevation along the route” is difficult. However, it becomes much easier if we reformulate it as the following decision problem:
Decision Problem: Given an elevation upper bound \(T\), can we reach point \(N\) from point \(1\) using only points with elevation at most \(T\), with at most \(K\) waypoints?
For this decision problem, the larger \(T\) is, the more points become available. This gives us monotonicity: “impossible when \(T\) is too small, possible when \(T\) is sufficiently large.” Therefore, we can find the value of \(T\) using binary search.
Issues with the Naive Approach
If we try every possible \(T\) and run BFS each time, there are up to \(N\) candidates for \(T\) and each BFS takes \(O(N + M)\), giving an overall complexity of \(O(N(N + M))\), which can be too slow when \(N\) and \(M\) are large. However, by reducing the number of candidates to \(O(\log N)\) through binary search, we achieve sufficient speed.
Binary Search Candidates
The only meaningful values for \(T\) are the actual elevation values that exist. We sort the elevation values and remove duplicates to form the candidate array. Furthermore, since points \(1\) and \(N\) must always be visited, we need \(T \geq \max(H_1, H_N)\).
Algorithm
- Prepare candidates: Sort all point elevations and remove duplicates. Keep only those that are at least \(\max(H_1, H_N)\).
- Binary search: Perform binary search over the candidate array. For each candidate \(T\), solve the decision problem.
- Decision (BFS): Using only points with elevation at most \(T\), run BFS from point \(1\). Since BFS finds the shortest path (the path with the minimum number of waypoints), we check whether the shortest number of waypoints to point \(N\) is at most \(K\).
- Result: Output the minimum \(T\) that satisfies the condition found by binary search. If no candidates exist or point \(N\) is unreachable even with the largest candidate, output \(-1\).
Concrete Example
For example, with \(N=4\), \(K=3\), elevations \(H = [2, 5, 3, 4]\), and edges \((1,2), (2,4), (1,3), (3,4)\):
- When \(T = 4\): Points with \(H \leq 4\) are \(\{1, 3, 4\}\). The path \(1 \to 3 \to 4\) exists with \(3\) waypoints \(\leq K\). → Possible
- When \(T = 3\): Points with \(H \leq 3\) are \(\{1, 3\}\). Point \(4\) (elevation \(4\)) cannot be used, so point \(N\) is unreachable. → Impossible
Therefore, the answer is \(4\).
Complexity
- Time complexity: \(O((N + M) \log N)\)
- Binary search runs \(O(\log N)\) times, each time performing BFS in \(O(N + M)\)
- Space complexity: \(O(N + M)\)
- For the adjacency list and BFS distance array
Implementation Details
BFS distance management: We treat
dist[v] = 0as “unvisited” and start withdist[1] = 1(the number of waypoints including point \(1\) itself is \(1\)), which keeps array initialization concise.Early termination: We immediately return the decision result as soon as point \(N\) is reached. Also, if the current number of waypoints has reached \(K\), we stop exploring further (
continuewhend >= K).Pre-check with the maximum candidate: Before binary search, we check whether point \(N\) is reachable using the largest candidate. If not, we immediately return \(-1\). This avoids unnecessary exploration.
Source Code
import sys
from collections import deque
def solve():
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
adj[u].append(v)
adj[v].append(u)
# Binary search on the answer (maximum height threshold)
# For a given threshold T, check if there's a path from 1 to N
# using only nodes with H[i] <= T, with path length <= K.
# We must always include nodes 1 and N, so T >= max(H[1], H[N]).
# Collect all unique heights
heights = sorted(set(H[1:N+1]))
# We need T >= H[1] and T >= H[N]
min_required = max(H[1], H[N])
# Filter heights that are >= min_required
# Binary search over these heights
candidates = [h for h in heights if h >= min_required]
if not candidates:
print(-1)
return
def check(threshold):
# BFS from node 1 to node N using only nodes with H[i] <= threshold
# Find shortest path (in terms of number of nodes) and check if <= K
if H[1] > threshold or H[N] > threshold:
return False
# BFS
dist = [0] * (N + 1) # 0 means unvisited
dist[1] = 1 # distance in terms of node count
queue = deque()
queue.append(1)
while queue:
u = queue.popleft()
d = dist[u]
if u == N:
return d <= K
if d >= K:
continue
for v in adj[u]:
if dist[v] == 0 and H[v] <= threshold:
dist[v] = d + 1
if v == N:
return dist[v] <= K
queue.append(v)
return False
# Binary search on candidates
lo, hi = 0, len(candidates) - 1
# First check if the largest candidate works
if not check(candidates[hi]):
print(-1)
return
while lo < hi:
mid = (lo + hi) // 2
if check(candidates[mid]):
hi = mid
else:
lo = mid + 1
print(candidates[lo])
solve()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: