Official

D - 迷宮からの脱出 / Escape from the Labyrinth Editorial by kyopro_friends Editorial for printing


この問題は 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)

posted:
last update: