公式

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, or O square → Cost 0 (no damage)
  • Moving to a P square → Cost 1 (damage +1)
  • Moving to a B square → 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

  1. Read the input and record the positions of S and G.
  2. Initialize the distance array dist[i][j] to \(\infty\), and set dist[sx][sy] = 0.
  3. Add the starting position to a double-ended queue (deque).
  4. 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\).
  5. 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 deque is the core of 0-1 BFS. Make sure not to forget using appendleft for cost 0 transitions and append for 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.

投稿日時:
最終更新: