// fedcba
000000 // 아무열쇠도 들고있지 않다
111111 // 모든 열쇠를 다 가지고 있다
000001 // a열쇠만 가지고 있다
010010 // e와b 열쇠를 가지고 있다
BFS{
3차원 방문배열 생성
큐 생성
큐에 시작값 추가
while(큐가 빌 때가지){
큐에서 현재위치를 꺼냄
if(지금 서있는 위치가 1이면) return cnt;
if(배열을 벗어나면) continue;
if(이미 동일한 조건으로 방문한 곳이면) continue;
if(문인데 알맞은 열쇠를 가지고 있지 않으면) continue;
else{
if(현재 위치가 열쇠면){열쇠값 갱신}
현재위치를 방문처리 후 큐에 삽입
}
}
}
import java.io.*;
import java.util.*;
class Main {
static int N, M;
static int[] dx = { 0, -1, 0, 1 };
static int[] dy = { -1, 0, 1, 0 };
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
char[][] board = new char[N][M];
for (int i = 0; i < N; i++) {
board[i] = br.readLine().toCharArray();
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (board[i][j] == '0') {
int[] start = { i, j, 0 };
board[i][j] = '.';
System.out.println(BFS(start, board));
break;
}
}
}
}
public static int BFS(int[] start, char[][] board) {
boolean[][][] v = new boolean[N][M][64];
v[start[0]][start[1]][start[2]] = true;
Queue<int[]> q = new LinkedList<int[]>();
q.add(start);
int cnt = 0;
while (!q.isEmpty()) {
int size = q.size();
while (--size >= 0) {
int[] now = q.poll();
if (board[now[0]][now[1]] == '1')
return cnt; // 탈출
for (int d = 0; d < 4; d++) {
int nx = now[0] + dx[d];
int ny = now[1] + dy[d];
if (nx < 0 || nx >= N || ny < 0 || ny >= M) continue; // 배열범위 밖
else if (board[nx][ny] == '#') continue; // 벽
else if (v[nx][ny][now[2]]) continue; // 방문했으면
else if (Character.isUpperCase(board[nx][ny]) && (now[2] & (1 << (board[nx][ny] - 'a'))) == 0) continue; // 문을 만났는데 열쇠가 없으면
else {
int key = now[2];
if (Character.isLowerCase(board[nx][ny])) { // 열쇠를 먹으면
key = (now[2] | (1 << (board[nx][ny] - 'a')));
}
int[] next = { nx, ny, key };
q.add(next);
v[nx][ny][now[2]] = true;
}
}
}
cnt++;
}
return -1;
}
}