公式
D - 迷宮からの脱出 / Escape from the Labyrinth 解説
by
D - 迷宮からの脱出 / Escape from the Labyrinth 解説
by
kyopro_friends
印刷ページ
この問題は BFS により解くことができます。
ロボットの動きは自身と高橋君の位置のみに基づいて決定的であることから、高橋君の位置とロボットの位置を状態としてBFSを行えばよいです。計算量は \(O((NM)^{K+1})\) になります
以下の実装例では、「高橋君の位置・ロボット1の位置・ロボット2の位置」を表す整数の6つ組を状態としています。ロボットが \(2\) 台未満のときは、ロボットの位置として常に \((-1,-1)\) を持つようにしています。
実装例 (C++)
#include <bits/stdc++.h>
using namespace std;
int main(){
int N, M, K;
cin >> N >> M >> K;
int Sr, Sc, Gr, Gc;
cin >> Sr >> Sc >> Gr >> Gc;
Sr--; Sc--;
Gr--; Gc--;
vector<int> pos;
for(int i=0; i<K; i++){
int p, q;
cin >> p >> q;
pos.push_back(p - 1);
pos.push_back(q - 1);
}
while(pos.size() < 4){
pos.push_back(-1);
}
vector<string> C(N);
for(int i=0; i<N; i++) cin >> C[i];
vector<array<int, 2>> d4 = {
{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {0, 0}
};
auto is_valid = [&](int r, int c){
return 0 <= r && r < N && 0 <= c && c < M && C[r][c] != '#';
};
queue<array<int, 6>> q;
q.push({Sr, Sc, pos[0], pos[1], pos[2], pos[3]});
map<array<int, 6>, int> visited;
while(q.size() > 0){
array<int, 6> state = q.front(); q.pop();
int turn = visited[state];
auto [pos0r, pos0c, pos1r, pos1c, pos2r, pos2c] = state;
for(auto [dr0, dc0]: d4){
int new_pos0r = pos0r + dr0;
int new_pos0c = pos0c + dc0;
if(!is_valid(new_pos0r, new_pos0c)) continue;
if((new_pos0r == pos1r && new_pos0c == pos1c) ||
(new_pos0r == pos2r && new_pos0c == pos2c)) continue;
if(new_pos0r == Gr && new_pos0c == Gc){
cout << turn + 1 << endl;
return 0;
}
auto next_pos = [&](int posir, int posic){
if(posir == -1) return make_pair(-1, -1);
vector<array<int, 4>> d;
for(int i=0; i<5; i++){
auto [dri, dci] = d4[i];
int new_posir = posir + dri;
int new_posic = posic + dci;
if(!is_valid(new_posir, new_posic)) continue;
int dist = abs(new_posir - new_pos0r) + abs(new_posic - new_pos0c);
d.push_back({dist, i, new_posir, new_posic});
}
auto [dist, i, new_posir, new_posic] = *min_element(d.begin(), d.end());
return make_pair(new_posir, new_posic);
};
auto [new_pos1r, new_pos1c] = next_pos(pos1r, pos1c);
auto [new_pos2r, new_pos2c] = next_pos(pos2r, pos2c);
if((new_pos0r == new_pos1r && new_pos0c == new_pos1c) ||
(new_pos0r == new_pos2r && new_pos0c == new_pos2c)) continue;
array<int, 6> new_state = {
new_pos0r, new_pos0c,
new_pos1r, new_pos1c,
new_pos2r, new_pos2c
};
if(!visited.contains(new_state)){
visited[new_state] = turn + 1;
q.push(new_state);
}
}
}
cout << -1 << endl;
}
実装例 (Python)
N, M, K = map(int, input().split())
Sr, Sc = map(int, input().split())
Gr, Gc = map(int, input().split())
Sr -= 1
Sc -= 1
Gr -= 1
Gc -= 1
pos = []
for _ in range(K):
p, q = map(int, input().split())
pos.append(p-1)
pos.append(q-1)
while len(pos) < 4:
pos.append(-1)
C = [input() for _ in range(N)]
d4 = [(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)]
def is_valid(r, c):
return 0 <= r < N and 0 <= c < M and C[r][c] != '#'
q = [(Sr, Sc, *pos)]
visited = {q[0]: 0}
for state in q:
turn = visited[state]
pos0r, pos0c, pos1r, pos1c, pos2r, pos2c = state
for dr0, dc0 in d4:
new_pos0r = pos0r + dr0
new_pos0c = pos0c + dc0
if not is_valid(new_pos0r, new_pos0c):
continue
if (new_pos0r == pos1r and new_pos0c == pos1c) or\
(new_pos0r == pos2r and new_pos0c == pos2c):
continue
if new_pos0r == Gr and new_pos0c == Gc:
print(turn + 1)
exit()
def move(posir, posic):
if posir == -1:
return (-1, -1)
d = []
for i, (dri, dci) in enumerate(d4):
new_posir = posir + dri
new_posic = posic + dci
if not is_valid(new_posir, new_posic):
continue
dist = abs(new_posir - new_pos0r) + abs(new_posic - new_pos0c)
d.append((dist, i, new_posir, new_posic))
_, _, new_posir, new_posic = min(d)
return new_posir, new_posic
new_pos1r, new_pos1c = move(pos1r, pos1c)
new_pos2r, new_pos2c = move(pos2r, pos2c)
if (new_pos0r == new_pos1r and new_pos0c == new_pos1c) or\
(new_pos0r == new_pos2r and new_pos0c == new_pos2c):
continue
new_state = (new_pos0r, new_pos0c, new_pos1r, new_pos1c, new_pos2r, new_pos2c)
if new_state not in visited:
visited[new_state] = turn + 1
q.append(new_state)
print(-1)
投稿日時:
最終更新:
