AtCoder上にある問題のうち、AtCoder Problemsでdiff 800以上と判定されているものを順番に解いていく企画。
基本的な考え方は全てコード中のコメントに入れてあるので、参照のこと。
出典:
AtCoder Grand Contest 033 A – Darker and Darker
毎回全てを探索するのではなく、その時々で必要な部分だけを探索していく、という問題。
# AtCoder Grand Contest 033 A - Darker and Darker
# https://atcoder.jp/contests/agc033/tasks/agc033_a
# グリッド キュー BFS
# 毎回グリッドを全て探索していては、間に合わない。
# ところで、毎回の操作で黒マスが少しずつ増えていくわけだが、
# その操作で黒マスになるのは、前回の操作で黒マスになった
# 地点の隣だけである。
# つまり、毎回全マスを探索するのではなく、前回黒マスになった
# 隣のマスだけを探索すればいい。これは一種のBFSとなる。
# 均すと、全てのマスは一回ずつ探索されることになるので
# O(HW) となる。
from collections import deque
def main():
H, W = map(int, input().split())
field = [[c for c in input()] for _ in range(H)]
moves = ((-1, 0), (1, 0), (0, -1), (0, 1))
# 黒マスに変わった手数を保存しておく配列。
# まだ白マスなら -1。
done = [[-1] * W for _ in range(H)]
# 初回のキューの作成
queue = deque()
for y in range(H):
for x in range(W):
if field[y][x] == '#':
queue.append((x, y))
done[y][x] = 0
result = 0
# 探索開始
while queue:
x, y = queue.pop()
for dx, dy in moves:
tx, ty = x + dx, y + dy
# 黒マスの隣がまだ白なら、黒マスに変えてキューの左に追加。
if 0 <= tx < W and 0 <= ty < H and done[ty][tx] == -1:
done[ty][tx] = done[y][x] + 1
queue.appendleft((tx, ty))
if result < done[ty][tx]:
result = done[ty][tx]
print(result)
main()
以下ちょっとだけ解き方を変えたオマケ。
# deque を使用せず、次回探索用のリストを作成し、
# 切り替えていく方式でも解ける。ついでに番兵法も用いてみた。
def main():
H, W = map(int, input().split())
# 番兵を置いておく。
# pythonは list[-1] で最後尾になるので、
# 置くのは一つだけでいい。
field = [[c for c in input()] + ['#'] for _ in range(H)]
field.append(['#'] * (W+1))
moves = ((-1, 0), (1, 0), (0, -1), (0, 1))
# 初回のキューの作成
queue = []
for y in range(H):
for x in range(W):
if field[y][x] == '#':
queue.append((x, y))
result = 0
# ここから探索。
while True:
new_queue = []
for x, y in queue:
for dx, dy in moves:
tx, ty = x + dx, y + dy
if field[ty][tx] == '.':
field[ty][tx] = '#'
new_queue.append((tx, ty))
# キューの更新。
queue = new_queue
if len(queue) > 0:
result += 1
else:
break
print(result)
main()