시작지점(S)에서 도착지점(E) 까지 가는데, 걸리는 최소거리를 구하는 문제다.
도착이 가능하면,
Escaped in X minute(s).
도착이 불가능하면,
Trapped!
로 출력하면된다.
import java.util.*;
import java.io.*;
public class 상범빌딩 {
static int L, R, C;
static char[][][] arr;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while(true) {
StringTokenizer st = new StringTokenizer(br.readLine());
L = Integer.parseInt(st.nextToken());
R = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
if(L==0 && R==0 && C==0) break;
arr = new char[L][R][C];
// start 위치
int[] startIdx = new int[3];
for (int t = 0; t < L; t++) {
for (int i = 0; i < R; i++) {
String s = br.readLine();
for (int j = 0; j < C; j++) {
arr[t][i][j] = s.charAt(j);
if(arr[t][i][j]=='S') {
startIdx[0] = t;
startIdx[1] = i;
startIdx[2] = j;
}
}
}
br.readLine();
}
int result = bfs(startIdx[0], startIdx[1], startIdx[2]);
if(result == -1) {
System.out.println("Trapped!");
}else {
System.out.println("Escaped in " + result + " minute(s).");
}
}
}
static class Point {
int t, r, c, cnt;
Point(int t, int r, int c, int cnt){
this.t=t;
this.r=r;
this.c=c;
this.cnt=cnt;
}
}
static int[] dr = {0, 0, 1, -1};
static int[] dc = {1, -1, 0, 0};
private static int bfs(int t, int r, int c) {
Queue<Point> queue = new ArrayDeque<>();
queue.offer(new Point(t, r, c, 0));
boolean[][][] v = new boolean[L][R][C];
v[t][r][c] = true;
while(!queue.isEmpty()) {
Point p = queue.poll();
if(arr[p.t][p.r][p.c]=='E') {
return p.cnt;
}
// 상하좌우
for (int d = 0; d < 4; d++) {
int nr = p.r + dr[d];
int nc = p.c + dc[d];
if(nr<0 || nr>=R || nc<0 || nc>=C || arr[p.t][nr][nc]=='#' || v[p.t][nr][nc]) continue;
queue.offer(new Point(p.t, nr, nc, p.cnt+1));
v[p.t][nr][nc] = true;
}
// 층 이동
if(p.t+1<L && (arr[p.t+1][p.r][p.c]=='.' || arr[p.t+1][p.r][p.c]=='E') && !v[p.t+1][p.r][p.c]) {
queue.offer(new Point(p.t+1, p.r, p.c, p.cnt+1));
v[p.t+1][p.r][p.c] = true;
}
if(p.t-1>=0 && (arr[p.t-1][p.r][p.c]=='.' || arr[p.t-1][p.r][p.c]=='E') && !v[p.t-1][p.r][p.c]) {
queue.offer(new Point(p.t-1, p.r, p.c, p.cnt+1));
v[p.t-1][p.r][p.c] = true;
}
}
return -1;
}
}
필자는 문제를 자세하게 읽지 않아서, 문제를 풀 때 다음과 같은 실수를 했다.
1. 0 0 0 이 입력이 되기 전에는 무한루프로 입력을 받아야 하는데, 실행하면 한번만 입력받게 코드를 작성했다.
2. 층 이동을 할 때, 다음과 같이 범위 안에 있는 층일 경우 게속해서 Queue에 추가를 했다.
// 층 이동
for(int i=p.t+1; i<L; i++) {
if(arr[i][p.r][p.c]=='.' || arr[i][p.r][p.c]=='E' && !v[i][p.r][p.c]) {
queue.offer(new Point(i, p.r, p.c, p.cnt+1));
v[i][p.r][p.c] = true;
}
}
for(int i=p.t-1; i>=0; i--) {
if((arr[i][p.r][p.c]=='.' || arr[i][p.r][p.c]=='E') && !v[i][p.r][p.c]) {
queue.offer(new Point(i, p.r, p.c, p.cnt+1));
v[i][p.r][p.c] = true;
}
}
필자가 작성한 코드에서 개선할 수 있는 코드가 있는지 다른 사람이 작성한 코드를 확인해봤는데, 이동하는 배열을 4방탐색에서 6방탐색으로 다음과 같이 변경하면 코드 유지보수와 가독성도 좋아지는 것을 확인했다.
static int[] dt = {0, 0, 0, 0, 1, -1};
static int[] dr = {0, 0, 1, -1, 0, 0};
static int[] dc = {1, -1, 0, 0, 0, 0};
private static int bfs(int t, int r, int c) {
Queue<Point> queue = new ArrayDeque<>();
queue.offer(new Point(t, r, c, 0));
boolean[][][] v = new boolean[L][R][C];
v[t][r][c] = true;
while(!queue.isEmpty()) {
Point p = queue.poll();
if(arr[p.t][p.r][p.c]=='E') {
return p.cnt;
}
// 상하좌우 및 층 이동
for (int d = 0; d < 6; d++) {
int nt = p.t + dt[d];
int nr = p.r + dr[d];
int nc = p.c + dc[d];
if(nt <0 || nt >= L || nr<0 || nr>=R || nc<0 || nc>=C || arr[nt][nr][nc]=='#' || v[nt][nr][nc]) continue;
queue.offer(new Point(nt, nr, nc, p.cnt+1));
v[nt][nr][nc] = true;
}
}
return -1;
}
문제를 꼼꼼히 읽어보는 습관을 들이고, 가독성과 유지보수를 생각하고 코드를 작성하자.