통나무의 중심
을 기준으로 값을 확인하는 방식으로 문제를 풀었습니다.
통나무의 이동은 4방향이지만 통나무의 상태가 가로
냐 아니면 세로
냐에 따라 확인해야 할 값이 달라집니다.
통나무의 회전
은 다음 조건을 만족해야 합니다.
3x3
공간이 확보되어 있어야 합니다.3x3
공간에 1(나무)
이 없어야 합니다.가로로 방문한 공간을 세로로도 방문할 수 있어야 합니다.
import java.util.*;
import java.io.*;
public class Main {
static int N;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
char[][] board = new char[N][N];
for (int i = 0; i < N; i++) {
board[i] = br.readLine().toCharArray();
}
int[] center = findCenter(board, 'B');
int[] goal = findCenter(board, 'E');
System.out.println(BFS(board, center, goal));
}
// 나무의 중심 찾기
public static int[] findCenter(char[][] board, char symbol) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (board[i][j] == symbol) {
if (j + 1 < N && board[i][j + 1] == symbol) { // BBB
return new int[] { i, j + 1, 0 };
} else {
return new int[] { i + 1, j, 1 };
}
}
}
}
return new int[] {};
}
// BFS
public static int BFS(char[][] board, int[] center, int[] goal) {
boolean[][][] visited = new boolean[N][N][2]; // 가로로 방문하는 것과 세로로 방문하는 것이 다르기 때문에 3차원으로 구현해야 합니다.
visited[center[0]][center[1]][center[2]] = true;
Queue<int[]> q = new LinkedList<int[]>();
q.add(center);
int cnt = 0;
while (!q.isEmpty()) {
int size = q.size();
while (--size >= 0) {
int[] now = q.poll();
if (now[0] == goal[0] && now[1] == goal[1] && now[2] == goal[2]) {
return cnt;
}
List<int[]> moveList = canMoveList(board, now);
for (int i = 0; i < moveList.size(); i++) {
int[] next = moveList.get(i);
if (visited[next[0]][next[1]][next[2]])
continue;
visited[next[0]][next[1]][next[2]] = true;
q.add(next);
}
}
cnt++;
}
return 0;
}
public static List<int[]> canMoveList(char[][] board, int[] now) {
List<int[]> list = new LinkedList<int[]>();
int r, c, d;
d = now[2];
// 앞
r = now[0];
c = now[1] + 1;
if (d == 0) {
if (c + 1 < N && board[r][c + 1] != '1') {
list.add(new int[] { r, c, d });
}
} else {
if (c < N && 0 <= r - 1 && r + 1 < N && board[r - 1][c] != '1' && board[r][c] != '1'
&& board[r + 1][c] != '1') {
list.add(new int[] { r, c, d });
}
}
// 뒤
r = now[0];
c = now[1] - 1;
if (d == 0) {
if (0 <= c - 1 && board[r][c - 1] != '1') {
list.add(new int[] { r, c, d });
}
} else {
if (0 <= c && 0 <= r - 1 && r + 1 < N && board[r - 1][c] != '1' && board[r][c] != '1'
&& board[r + 1][c] != '1') {
list.add(new int[] { r, c, d });
}
}
// 위
r = now[0] - 1;
c = now[1];
if (d == 0) {
if (0 <= r && 0 <= c - 1 && c + 1 < N && board[r][c - 1] != '1' && board[r][c] != '1'
&& board[r][c + 1] != '1') {
list.add(new int[] { r, c, d });
}
} else {
if (0 <= r - 1 && board[r - 1][c] != '1') {
list.add(new int[] { r, c, d });
}
}
// 아래
r = now[0] + 1;
c = now[1];
if (d == 0) {
if (r < N && 0 <= c - 1 && c + 1 < N && board[r][c - 1] != '1' && board[r][c] != '1'
&& board[r][c + 1] != '1') {
list.add(new int[] { r, c, d });
}
} else {
if (r + 1 < N && board[r + 1][c] != '1') {
list.add(new int[] { r, c, d });
}
}
// 회전
r = now[0];
c = now[1];
boolean flag = true;
if (0 > r - 1 || r + 1 >= N || 0 > c - 1 || c + 1 >= N) { // 3x3공간을 확보하지 못하면 회전할 수 없습니다.
flag = false;
}
for (int i = r - 1; i <= r + 1; i++) {
for (int j = c - 1; j <= c + 1; j++) {
if (0 <= i && i < N && 0 <= j && j < N && board[i][j] == '1') { // 3x3공간에 1이 존재하면 회전할 수 없습니다.
flag = false;
}
}
}
if (flag) {
list.add(new int[] { r, c, Math.abs(d - 1) });
}
return list;
}
}