D - 迷路と罠マス / Maze and Trap Squares 解説 by admin
Claude 4.6 Opus (Thinking)Overview
This is a problem where you move from the start position S to the goal G on a maze, minimizing the number of times you step on trap squares P (cumulative damage). It can be reduced to a shortest path problem where edge weights are only 0 or 1, and can be efficiently solved using 0-1 BFS.
Analysis
Key Insight
In this problem, the cost of moving to an adjacent square is limited to only two types:
- Moving to an
S,G, orOsquare → Cost 0 (no damage) - Moving to a
Psquare → Cost 1 (damage +1) - Moving to a
Bsquare → Movement impossible
In other words, if we consider the grid as a graph, this becomes a shortest path problem on a graph where edge weights are either 0 or 1.
Issues with the Naive Approach
Dijkstra’s algorithm (with a priority queue) could solve this, but priority queue operations cost \(O(\log N)\). Since \(H \times W\) can be as large as \(10^6\), this may be too slow in Python due to constant factor overhead.
Solution: 0-1 BFS
When edge weights are limited to only two values, 0 and 1, we can use a technique called 0-1 BFS. While normal BFS uses a FIFO queue (deque), 0-1 BFS adds elements to the queue according to the following rules:
- Transition via a cost 0 edge → Add to the front of the queue (
appendleft) - Transition via a cost 1 edge → Add to the back of the queue (
append)
By doing this, the contents of the queue always remain sorted by cost, so we can correctly compute shortest distances without using a priority queue.
Algorithm
- Read the input and record the positions of
SandG. - Initialize the distance array
dist[i][j]to \(\infty\), and setdist[sx][sy] = 0. - Add the starting position to a double-ended queue (deque).
- Repeat the following until the queue is empty:
- Pop the coordinates \((x, y)\) from the front of the queue.
- If \((x, y)\) is the goal, output
dist[x][y]and terminate. - Check the four adjacent squares \((nx, ny)\) (up, down, left, right):
- Skip if out of bounds or
B. - Calculate the movement cost \(c\) (1 if
P, 0 otherwise). - If
dist[x][y] + c < dist[nx][ny], update the distance and add to the front of the queue if \(c = 0\), or to the back of the queue if \(c = 1\).
- Skip if out of bounds or
- If the goal is unreachable, output
-1.
Concrete Example
3 3
S O P
O B P
O O G
By going S(0,0) → (1,0) → (2,0) → (2,1) → (2,2) = G, we can reach the goal with cost 0, without stepping on any trap P. On the other hand, going S(0,0) → (0,2) → (1,2) → (2,2) = G would step on P twice, resulting in cost 2. Since 0-1 BFS prioritizes processing cost 0 transitions, the minimum cost path is found first.
Complexity
- Time complexity: \(O(H \times W)\)
- Each square is added to the queue at most a constant number of times, and we check at most 4 directions from each square.
- Space complexity: \(O(H \times W)\)
- For the distance array and the queue.
Implementation Notes
Properly using
dequeis the core of 0-1 BFS. Make sure not to forget usingappendleftfor cost 0 transitions andappendfor cost 1 transitions.You can immediately output the answer and terminate as soon as the goal is popped from the queue. This is because in 0-1 BFS, the shortest distance to a vertex is finalized at the moment it is popped from the queue.
In Python, reading input all at once with
sys.stdin.buffer.read()can speed things up.Source Code
import sys
from collections import deque
def main():
input_data = sys.stdin.buffer.read().decode()
tokens = input_data.split()
idx = 0
H = int(tokens[idx]); idx += 1
W = int(tokens[idx]); idx += 1
grid = []
sx = sy = gx = gy = 0
for i in range(H):
row = tokens[idx]; idx += 1
grid.append(row)
for j in range(len(row)):
if row[j] == 'S':
sx, sy = i, j
elif row[j] == 'G':
gx, gy = i, j
# 0-1 BFS: cost 0 for S/G/O, cost 1 for P, B is wall
INF = float('inf')
dist = [[INF] * W for _ in range(H)]
dist[sx][sy] = 0
dq = deque()
dq.append((sx, sy))
dirs = ((1, 0), (-1, 0), (0, 1), (0, -1))
while dq:
x, y = dq.popleft()
d = dist[x][y]
if x == gx and y == gy:
print(d)
return
for dx, dy in dirs:
nx, ny = x + dx, y + dy
if 0 <= nx < H and 0 <= ny < W:
c = grid[nx][ny]
if c == 'B':
continue
nd = d + (1 if c == 'P' else 0)
if nd < dist[nx][ny]:
dist[nx][ny] = nd
if c == 'P':
dq.append((nx, ny))
else:
dq.appendleft((nx, ny))
print(dist[gx][gy] if dist[gx][gy] < INF else -1)
main()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: