[BOJ] 13460.구슬탈출2
- 내가 찾은 테케:
5 5
#####
#..R#
#.#.#
#BO.#
#####
- 위의 경우에서 처음에 flag처리를 위치가 잘못되어서 결과가 4가 나왔다. 하지만 옳은 답은 2가 나와야해서 이 경우를 처리한 후 “맞았습니다!!” 결과를 볼 수 있었다!
- 메모리 : 13,116 KB
- 실행시간 : 76 ms
- 코드길이 : 3,476 B
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main_B_13460_구슬탈출2 {
static Point point;
static int N, M;
static char[][] board;
static boolean[][][][] visited;
static int[][] delta = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } }; // 상, 우, 하, 좌
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(in.readLine(), " ");
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
board = new char[N][M];
visited = new boolean[N][M][N][M];
point = new Point();
for (int i = 0; i < N; i++) {
String tmp = in.readLine();
for (int j = 0; j < M; j++) {
board[i][j] = tmp.charAt(j);
if (board[i][j] == 'R') {
point.rx = i;
point.ry = j;
} else if (board[i][j] == 'B') {
point.bx = i;
point.by = j;
}
}
}
System.out.println(move());
in.close();
} // end main
// bfs
private static int move() {
Queue<Point> queue = new LinkedList<Point>();
queue.add(point);
while (!queue.isEmpty()) {
Point cur = queue.poll();
visited[cur.rx][cur.ry][cur.bx][cur.by] = true;
// 10회 이상이라면 더 돌릴 필요 없이 break;
if (cur.cnt >= 10) {
return -1;
}
for (int n = 0; n < delta.length; n++) {
boolean flagRed = false;
boolean flagBlue = false;
// 이전에 이동했던 방향의 반대방향으로 이동하지 못하도록 예외처리
if (cur.dir != -1 && n == ((cur.dir % 4) + 2) % 4)
continue;
int rx = cur.rx;
int ry = cur.ry;
// 벽이나 구멍을 만날때까지 무조건 이동
while (true) {
rx += delta[n][0];
ry += delta[n][1];
// 벽을 만나면 하나 빼서 .인 자리로 이동
if (board[rx][ry] == '#') {
rx -= delta[n][0];
ry -= delta[n][1];
break;
}
if (board[rx][ry] == 'O') {
flagRed = true;
break;
}
}
int bx = cur.bx;
int by = cur.by;
while (true) {
bx += delta[n][0];
by += delta[n][1];
if (board[bx][by] == '#') {
bx -= delta[n][0];
by -= delta[n][1];
break;
}
if (board[bx][by] == 'O') {
flagBlue = true;
break;
}
}
// 빨간 구슬만 빠졌다면 더 볼필요 없이 return
if (flagRed && !flagBlue) {
return cur.cnt + 1;
}
// 파란 구슬만 빠진 경우 다시 돌면서 다른 경우 있나 탐색
else if (flagBlue) {
continue;
}
// 제자리라면 다시 continue
if (rx == cur.rx && ry == cur.ry && bx == cur.bx && by == cur.by)
continue;
// 제자리가 아니고 다 굴러서 이동했는데 같은 자리라면
if (rx == bx && ry == by) {
switch (n) {
case 0: // 상
if (cur.rx > cur.bx) { // 초기 위치에서 빨간 구슬이 더 위에 있었다면
rx += 1;
} else {
bx += 1;
}
break;
case 1: // 우
if (cur.ry > cur.by) { // 빨간 구슬이 더 우측에 존재했다면
by -= 1;
} else {
ry -= 1;
}
break;
case 2: // 하
if (cur.rx > cur.bx) { // 빨간 구슬이 더 아래에 위치했다면
bx -= 1;
} else {
rx -= 1;
}
break;
case 3: // 좌
if (cur.ry > cur.by) { // 빨간 구슬이 저 왼쪽에 위치했다면
ry += 1;
} else {
by += 1;
}
break;
}
}
// 방문하지 않았던 좌표라면
// -> 빨간 구슬과 파란 구슬 모두를 체크하는 이유는
// 빨간 구슬의 위치가 같은데 파란 구슬의 위치는 다른 경우도 존재하기 때문에!
if (!visited[rx][ry][bx][by]) {
queue.add(new Point(rx, ry, bx, by, cur.cnt + 1, n));
}
} // end for delta
} // end while
return -1;
}
static class Point {
int rx;
int ry;
int bx;
int by;
int cnt;
int dir;
public Point() {
this.cnt = 0;
this.dir = -1;
}
public Point(int rx, int ry, int bx, int by, int cnt, int dir) {
this.rx = rx;
this.ry = ry;
this.bx = bx;
this.by = by;
this.cnt = cnt;
this.dir = dir;
}
}
}
Leave a comment