문제
풀이
처음 접근 방법은 DFS였으나 방문처리 과정에서 코드가 꼬여 풀이법을 참고한 결과 BFS로 쉽게 풀릴 수 있는 문제임을 알았다. 처음엔 빨간 구슬의 방문처리만 해줬는데 이동하는 한칸한칸 모두 해주다보니 원하는 결과가 나오지 않았다. 방문처리는 구슬을 굴렸을 때 벽에 부딪히거나 ‘O’에 들어갔을 때의 그 위치만 해주면 되는데 한칸한칸 방문처리를 해주다 보니 이상한곳에 시간을 낭비했다 ㅠㅠ…
또한 4방향 탐색에서 벽(#)인 부분이 있으면 애초에 갈 생각도 안했는데 반례를 찾다보니 빨간 구슬의 4방향을 모두 탐색해야지만 풀리는 테스트케이스가 있음을 깨달았다.(예를 들어 파란구슬을 가두어 둔 뒤 빨간구슬을 움직이는 경우)
그리고 queue에 구슬의 위치를 저장할 때, 난 방문처리를 미리 해준 뒤에 저장했는데 구슬을 먼저 굴려보고 구슬의 현재 위치가 이미 갔던 곳이지 확인을 한 뒤 처음 방문일때만 queue에 저장을 해줘야했다.
문제에 나와있는 모든 조건을 코드에 담으려 하지 않아도 문제는 풀렸다. 파란구슬이 ‘O’에 빠지면 무조건 -1을 출력한다는 편견과 두 구슬이 위치가 같을 수 있고 그럴 경우엔 계산을 해서 위치를 바꿔주면 되는데 빨간구슬 먼저 움직이고 파란구슬 움직이고… 순서를 정할 필요가 없었다 ㅠㅠ
첫 통과때의 메모리는 177024 KB에 시간은 628 ms가 걸렸는데 공개가 되어있는 다른 사람들의 풀이를 참고해 차근차근 다시 풀었고, 14916 KB, 140 ms 라는 최적값을 낼 수 있었다.
풀이
import java.io.*;
import java.util.*;
public class Main {
static Queue<Point> queue = new LinkedList<>();
static char[][] map;
static boolean visited[][][][];
static int N, M;
static int[][] dir = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
static class Point {
int rx, ry, bx, by, count;
}
static Point startPoint = new Point();
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());
map = new char[N][M];
visited = new boolean[N][M][N][M];
for (int i = 0; i < N; i++) {
String tmp = br.readLine();
for (int j = 0; j < M; j++) {
map[i][j] = tmp.charAt(j);
if (map[i][j] == 'R') {
startPoint.rx = i;
startPoint.ry = j;
}
if (map[i][j] == 'B') {
startPoint.bx = i;
startPoint.by = j;
}
}
}
startPoint.count = 0;
System.out.println(bfs());
}
public static int bfs() {
int result = -1;
/* 1. 큐에 시작점 넣고 방문처리 해주기 */
queue.add(startPoint);
visited[startPoint.rx][startPoint.ry][startPoint.bx][startPoint.by] = true;
/* 2. bfs 돌리기 */
while (!queue.isEmpty()) {
Point now = queue.poll();
if (now.count > 10)
break; // 10번 이하로만 굴리기
if (map[now.rx][now.ry] == 'O' && map[now.bx][now.by] != 'O') {
result = now.count;
break;
}
/* 4방향 탐색 */
for (int d = 0; d < 4; d++) {
int nrx = now.rx;
int nry = now.ry;
int nbx = now.bx;
int nby = now.by;
// 공 굴리기
int[] red = move(nrx, nry, d);
nrx = red[0];
nry = red[1];
int[] blue = move(nbx, nby, d);
nbx = blue[0];
nby = blue[1];
// 빨간공과 파란공 위치가 같으면 위치를 수정해준다.
if (nrx == nbx && nry == nby) {
if (map[nrx][nry] != 'O') {
int rdist = Math.abs(nrx - now.rx) + Math.abs(nry - now.ry);
int bdist = Math.abs(nbx - now.bx) + Math.abs(nby - now.by);
if (rdist > bdist) { // 빨간공이 파란공보다 뒤에 있다.
nrx -= dir[d][0];
nry -= dir[d][1];
} else {
nbx -= dir[d][0];
nby -= dir[d][1];
}
}
}
/* 4. 방문 안한 Point를 큐에 넣고 방문처리 해준다. */
if (!visited[nrx][nry][nbx][nby]) {
Point newPoint = new Point();
newPoint.rx = nrx;
newPoint.ry = nry;
newPoint.bx = nbx;
newPoint.by = nby;
newPoint.count = now.count + 1;
queue.add(newPoint);
visited[nrx][nry][nbx][nby] = true;
}
}
}
return result;
}
public static int[] move(int x, int y, int d) {
while (true) {
if (map[x][y] != '#' && map[x][y] != 'O') {
x += dir[d][0];
y += dir[d][1];
} else {
if (map[x][y] == '#') {// 'O'일 수 있으니까
x -= dir[d][0];
y -= dir[d][1];
}
break;
}
}
return new int[] { x, y };
}
}
반례
4 5
#####
#.BR#
#.O##
#####
answer : 2
10 9
#########
#.##....#
#.#.#####
#####...#
#.####R##
####....#
###BO####
#.#.###.#
###...#.#
#########
answer : 3
7 6
######
##..B#
#..#.#
#R...#
##..O#
#....#
######
answer : 4
5 5
#####
#.#.#
#####
#BOR#
#####
answer : 1
6 6
######
##...#
#...##
#B.###
#OR#.#
######
answer : 1
8 6
######
#.BR.#
##O.##
#....#
##...#
#..###
#....#
######
answer : 2
9 7
#######
##.##.#
####.##
###O###
#..BR.#
###.#.#
#.#...#
##.#..#
#######
answer : 5
8 5
#####
###.#
#.O##
##BR#
##.##
#..##
#.###
#####
answer : 3
5 5
#####
#.#R#
###.#
#.BO#
#####
answer : 1
8 8
########
#.#.####
######.#
#..#.###
#BO..R.#
#.#...##
##.###.#
########
answer : 1
9 6
######
#.B#.#
#..R##
##.#.#
#..#.#
#O.#.#
#..#.#
#....#
######
answer : 9
6 7
#######
#.#.R##
#B..#.#
#.....#
#O#..##
#######
answer : 6
10 6
######
#BO.##
#...##
###.##
##...#
###..#
###R##
#.#..#
##.#.#
######
answer : 2
5 9
#########
#.##....#
#..R..###
#O#B##..#
#########
answer : 2
8 7
#######
##.####
#.##.B#
##...R#
###..O#
##..#.#
#####.#
#######
answer : 6
9 9
#########
##.R..###
##..#####
###.#.#.#
##.B#.#.#
#.....###
#.O..#.##
###..####
#########
answer : 2
7 5
#####
###O#
#...#
##.##
##..#
#.BR#
#####
answer : 4
6 10
##########
##O..#..##
#.#.##.###
#.#..B..R#
#######.##
##########
answer : 5
8 5
#####
#.###
#...#
#...#
#O.##
#.###
#.RB#
#####
answer : 2