倉庫の 通路で ゴールまでの 最短の歩数
- 迷路と盤面
- 問題 14
- ふつう
- 目安 31 分
棚と
本番の
入力は
問題
ある
.は通路で、通れます #は棚で、 通れません Sはスタートの 位置で、通れます Gはゴールの 位置で、通れます
作業員は 1 歩で、
入力の形式
H W
s_1
s_2
...
s_H1 行目に
出力の形式
最少の
制約
- H と W は、
どちらも 1 以上 500 以下です。 H × W は 2 以上です - 地図は
.#SGの 4 種類の文字だけで できています SとGは、地図の 中に ちょうど 1 つずつあります
入力と出力の例
例 1
左上の
入力
3 4 S.#. .#.. ...G
出力
5
例 2
真ん中の
入力
2 3 S#G .#.
出力
-1
ヒント
まだ開いていません
付箋は 3 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3答えに近い
全部の
先に
解答
S から
Python
Python
import sys
from collections import deque
data = sys.stdin.read().split()
h, w = int(data[0]), int(data[1])
grid = data[2:2 + h]
for r in range(h):
for c in range(w):
if grid[r][c] == "S":
start = (r, c)
elif grid[r][c] == "G":
goal = (r, c)
dist = [[-1] * w for _ in range(h)]
dist[start[0]][start[1]] = 0
queue = deque([start])
while queue:
r, c = queue.popleft()
if (r, c) == goal:
break
for nr, nc in ((r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)):
if 0 <= nr < h and 0 <= nc < w and grid[nr][nc] != "#" and dist[nr][nc] == -1:
dist[nr][nc] = dist[r][c] + 1
queue.append((nr, nc))
print(dist[goal[0]][goal[1]])JavaScript
JavaScript
const lines = require("fs").readFileSync(0, "utf8").split(/\s+/).filter(Boolean);
const [h, w] = lines.slice(0, 2).map(Number);
const grid = lines.slice(2, 2 + h);
let start = null;
let goal = null;
for (let r = 0; r < h; r++) {
for (let c = 0; c < w; c++) {
if (grid[r][c] === "S") start = [r, c];
else if (grid[r][c] === "G") goal = [r, c];
}
}
const dist = Array.from({ length: h }, () => new Array(w).fill(-1));
dist[start[0]][start[1]] = 0;
const queue = [start];
let head = 0;
while (head < queue.length) {
const [r, c] = queue[head++];
if (r === goal[0] && c === goal[1]) break;
for (const [nr, nc] of [[r - 1, c], [r + 1, c], [r, c - 1], [r, c + 1]]) {
if (nr >= 0 && nr < h && nc >= 0 && nc < w && grid[nr][nc] !== "#" && dist[nr][nc] === -1) {
dist[nr][nc] = dist[r][c] + 1;
queue.push([nr, nc]);
}
}
}
console.log(dist[goal[0]][goal[1]]);計算量
時間は O(H × W) です。
遅い
よく ある間違い
- 待ち行列に
入れる ときではなく、 取り出した ときに 「来た」と 印を 付ける。 同じ マスが 何度も 列に 入り、 遅くなったり、 メモリが 足りなくなったりします - Python で list の pop(0) を
使って 前から 取り出す。 1 回ごとに 全体を ずらすので O(列の 長さ) かかり、 大きな 迷路で 遅くなります。 deque の popleft() を使います - 深さ優先探索で
最初に 見つけた 道の 歩数を 答えに する。 深さ優先では、 最初に 着いた 道が 最短とは 限りません - 行と
列を 取り違える。 入力は H 行 W 列で、 grid[r][c] の r が 行 (0 以上 H 未満)、 c が 列 (0 以上 W 未満) です - ゴールに
行けない ときに -1 を 出さず、 何も 出力しないか、 大きな 数を 出してしまう
解答を動かした版 Python 3.12.14Node.js 22.23.4確認日 2026/10/31