ABC176 D - Wizard in Maze
備忘録
問題
回答
import sys, os, math, bisect, itertools, collections, heapq, queue, copy, array # from scipy.sparse.csgraph import csgraph_from_dense, floyd_warshall # from decimal import Decimal # from collections import defaultdict, deque sys.setrecursionlimit(10000000) ii = lambda: int(sys.stdin.buffer.readline().rstrip()) il = lambda: list(map(int, sys.stdin.buffer.readline().split())) fl = lambda: list(map(float, sys.stdin.buffer.readline().split())) iln = lambda n: [int(sys.stdin.buffer.readline().rstrip()) for _ in range(n)] iss = lambda: sys.stdin.buffer.readline().decode().rstrip() sl = lambda: list(map(str, sys.stdin.buffer.readline().decode().split())) isn = lambda n: [sys.stdin.buffer.readline().decode().rstrip() for _ in range(n)] lcm = lambda x, y: (x * y) // math.gcd(x, y) MOD = 10 ** 9 + 7 INF = float('inf') def main(): if os.getenv("LOCAL"): sys.stdin = open("input.txt", "r") H, W = il() Ch, Cw = il() Dh, Dw = il() grid = [iss() for _ in range(H)] visited = [[INF] * W for _ in range(H)] move = [[-1, 0], [1, 0], [0, -1], [0, 1]] que = collections.deque() que.appendleft((Ch - 1, Cw - 1, 0)) visited[Ch - 1][Cw - 1] = 0 while que: h, w, c = que.popleft() for mh, mw in move: # 移動A: 歩いて移動 ch, cw = h + mh, w + mw if 0 <= ch < H and 0 <= cw < W and grid[ch][cw] != '#' and visited[ch][cw] > c: visited[ch][cw] = c que.appendleft((ch, cw, c)) for wh in range(-2, 3): # 移動B: ワープ魔法 for ww in range(-2, 3): ch, cw = h + wh, w + ww if 0 <= ch < H and 0 <= cw < W and grid[ch][cw] != '#' and visited[ch][cw] > c + 1: visited[ch][cw] = c + 1 que.append((ch, cw, c + 1)) ret = visited[Dh - 1][Dw - 1] print(-1 if ret == INF else ret) if __name__ == '__main__': main()
考え方
上記のコードはPython (3.8.2)
で提出を行ったらTLEだったため、
PyPy3 (7.3.0)
で提出を行った。
BFS(深さ優先探索)を用いて、移動範囲を探索する。
歩いて移動できる範囲をコスト0で移動できるマス、
ワープ魔法で移動できる範囲をコスト1で移動できるマスと考え、
01-BFSを用いた回答を行う。
公式の解説通り、歩いて移動できる範囲をコスト0、ワープ魔法で移動できる範囲をコスト1と考えることで、
移動におけるコストが0と1だけなので、01-BFSで回答を行うことが出来る。
01-BFSの理解は以下の解説を読んだ。
簡単に言ってしまえば、両端キューを用意し、
移動コストが必要ない移動についてはキューの先頭に追加、
移動コストが必要な場合にはキューの末尾に追加する。
あとは先頭からキューを取り出し、再び移動範囲の探索を行なう。
実装は(h, w, (h,w)までの移動コスト)
を持ったキューを用意し、
取り出したキューから歩いた場合と魔法で移動した場合の移動範囲を全て探索する。
なお、この時の探索は制約で与えられたグリッドの範囲内かつ、
移動コストを減少させることができる移動のみをキューに積んでいく。
追記:徒歩移動とワープ移動を別々のキューに持たせることで200msぐらい早くなった。
しかし、相変わらずPython (3.8.2)
では通せない。。。
https://atcoder.jp/contests/abc176/submissions/16181571