AOJ 1166: 迷図と命ず / Amazing Mazes

問題

問題文

問題概要

迷路を表すデータが与えられる.

入口から出口までの最短経路の長さを求めよ.

制約

解答例

指針

  • BFS

解説

二次元グリッド上の最短経路問題なので幅優先探索(Breadth First Search: BFS)をすればいいのは, すぐに分かる.

しかし迷路の壁のデータが与えられるという少しトリッキーな形式なので注意が必要.

各座標の4方向に関して, 移動できるかどうかを値として保持するようにすればこの問題を解くことができる.

  • C++ による実装例
// submission: https://onlinejudge.u-aizu.ac.jp/status/users/kira924age/submissions/1/1166/judge/4082763/C++

#include <iostream>
#include <queue>

using namespace std;

int h, w;
// maze[y][x][i] = 1 -> (x, y) は (dx[i], dy[i]) 方向に移動可能
int maze[100][100][4];
int dist[100][100];
int dx[4] = {-1, 0, 0, 1};
int dy[4] = {0, 1, -1, 0};

struct sets { int x, y, d; };

void init() {
  for (int i = 0; i < 100; i++) {
    for(int j = 0; j < 100; j++) {
      for (int k = 0; k < 4; k++) {
        maze[i][j][k] = 0;
      }
    }
  }
  for (int i = 0; i < 100; i++) {
    for (int j = 0; j < 100; j++) {
      dist[i][j] = -1;
    }
  }
}

int bfs() {
  queue<sets> q;
  q.push( sets{0, 0, 0} );
  dist[0][0] = 0;

  while (!q.empty()) {
    sets cur = q.front(); q.pop();
    int x = cur.x;
    int y = cur.y;
    int d = cur.d;
    for (int i = 0; i < 4; i++) {
      int nx = x + dx[i];
      int ny = y + dy[i];

      if ( maze[y][x][i] == 0 ) { continue; }
      if ( dist[ny][nx] != -1 ) { continue; }

      q.push( sets{nx, ny, d+1} );
      dist[ny][nx] = d+1;
    }
  }
  return dist[h-1][w-1] + 1;
}

int main() {
  while (cin >> w >> h) {
    if (h == 0 && w == 0) { break; }
    init();
    for (int i = 0; i < 2*h-1; i++) {
      if (i & 1) {
        for (int j = 0; j < w; j++) {
          int t; cin >> t;
          if (t == 0) {
            maze[i/2][j][1] = 1;
            maze[i/2+1][j][2] = 1;
          }
        }
      } else {
        for (int j = 0; j < w-1; j++) {
          int t; cin >> t;
          if (t == 0) {
            maze[i/2][j][3] = 1;
            maze[i/2][j+1][0] = 1;
          }
        }
      }
    }
    cout << bfs() << endl;
  }
  return 0;
}
  • Python3 による実装例
# submission: https://onlinejudge.u-aizu.ac.jp/status/users/kira924age/submissions/1/1166/judge/4082821/Python3

import queue

def bfs(w, h, maze):
    dx = [-1, 0, 0, 1]
    dy = [0, 1, -1, 0]
    dist = [ [-1] * (w+1) for _ in range(h+1) ]
    q = queue.Queue()
    q.put([0, 0, 0])
    dist[0][0] = 0

    while not q.empty():
        x, y, d = q.get()
        for i in range(4):
            nx = x+dx[i]
            ny = y+dy[i]

            if maze[y][x][i] == 0: continue
            if dist[ny][nx] != -1: continue
            
            q.put( [nx, ny, d+1] )
            dist[ny][nx] = d+1

    return dist[h-1][w-1] + 1

while True:
    w, h = map(int, input().split())
    if w == 0 and h == 0: break
    maze = [ [[0] * 4 for x in range(w+1)] for _ in range(h+1) ]

    for i in range(h*2-1):
        if i & 1:
            t = [ int(x) for x in input().split() ]
            for j, tt in enumerate(t):
                if tt == 0:
                    maze[i//2][j][1] = 1
                    maze[i//2+1][j][2] = 1
        else:
            t = [ int(x) for x in input().split() ]
            for j, tt in enumerate(t):
                if tt == 0:
                    maze[i//2][j][3] = 1
                    maze[i//2][j+1][0] = 1
    print(bfs(w, h, maze))