atcoder.jp
問題
- $N\times N$のグリッド板があるよ
- 各マスは、空きマス、障害物のどちらかだよ
- プレイヤーのコマが盤上に2つ存在するよ
- 板を上に傾けると、プレイヤーのコマが同時に1マス上に移動しようとするよ
- 移動先が障害物なら、そのプレイヤーは動けないよ
- 右、左、下に関しても同じだよ
- プレイヤーのコマを同じマスに集めたいよ。最小手数を教えてね
成約
- $2 \leq N \leq 2\times 60$
- プレイヤーのコマは2つ
思考
- 終わり盤面から見ていこうとした時点で負け確定
- 成約が小さいので、全部の情報を盛り込んじゃえばどうにでもなる話だった
- 盤面は$60 \times 60$なので、最大3600マス
- プレイヤー1が存在する場所は高々3600マス、プレイヤー2も同様
- $ 3600 \times 3600 = 12,960,000$
- (プレイヤー1の場所、プレイヤー2の場所)を持って、初期盤面から何手かかる?のBFSで終わり
- これが解けなかったのは、とても、つらい…
コード
from collections import deque
N = int(input())
grid_L = []
for i in range(N):
S = input()
grid_L += list(S)
P_L = []
for i in range(N):
for j in range(N):
if grid_L[i*N+j] == "P":
P_L.append((i*N+j))
ans_L = [-1]*(N*N*N*N)
ans_L[P_L[0]*(N*N)+P_L[1]] = ans_L[P_L[1]*(N*N)+P_L[0]] = 0
dir = [-N,1,N,-1]
que = deque([P_L[0]*(N*N)+P_L[1],P_L[1]*(N*N)+P_L[0]])
while que:
status = que.popleft()
now_score = ans_L[status]
p1 = status // (N*N)
p2 = status % (N*N)
if p1 == p2:
print(now_score)
exit()
for d in dir:
if 0 <= p1+d < N*N and grid_L[p1+d] != "#" and (p1 % N == (p1+d) % N or p1//N == (p1+d) // N):
np1 = p1+d
else:
np1 = p1
if 0 <= p2+d < N*N and grid_L[p2+d] != "#" and (p2 % N == (p2+d) % N or p2//N == (p2+d) // N):
np2 = p2+d
else:
np2 = p2
if ans_L[np1*(N*N)+np2] == -1:
ans_L[np1*(N*N)+np2] = now_score + 1
que.append(np1*(N*N)+np2)
if ans_L[np2*(N*N)+np1] == -1:
ans_L[np2*(N*N)+np1] = now_score + 1
que.append(np2*(N*N)+np1)
print(-1)