너무너무너무 어렵다... 보통 이런 유형의 문제는 지시하는 바를 순서대로 반복 수행하면 되는 것이였으나 이 문제는 최악의 경우에 맵이 무려 1500 x 1500 이다. 따라서 매번 새롭게 BFS를 수행한다거나 방문체크를 수행시 마다 리셋하는 것은 불가능하다.
이 문제의 핵심은 다음과 같다.
다음 큐
와 현재 큐 사이즈만큼만 BFS를 수행
를 통해 매번 처음부터 탐색을 수행하는 것이 아니라 이전에 탐색을 중지한 지점에서 이어 진행하는 것이다.구현 순서는 다음과 같다.
데이터를 입력받는다.
탐색 큐에 첫 번째 백조를 넣고 방문체크한다.
탐색 큐로 BFS 탐색을 실시한다.
탐색이 종료된 후 다음 큐를 탐색 큐로 바꾼다.
워터 큐에 있는 물과 인접한 얼음을 녹이고 그 지점을 다시 워터 큐에 넣는다.
날짜를 1 증가시키고 3.으로 돌아간다.
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 {
static class Node {
int r, c;
Node(int r, int c) {
this.r = r;
this.c = c;
}
}
static Queue<Node> q;
static Queue<Node> waterQ;
static int[][] dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
static char[][] map;
static boolean[][] visited;
static Node[] swan;
static int R, C;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
R = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
waterQ = new LinkedList<>();
q = new LinkedList<>();
swan = new Node[2];
map = new char[R][C];
visited = new boolean[R][C];
// 데이터 입력
int swanIdx = 0;
for(int r = 0 ; r < R ; ++r) {
char[] line = br.readLine().toCharArray();
for(int c = 0 ; c < C ; ++c) {
map[r][c] = line[c];
if(map[r][c] == 'L') {
swan[swanIdx++] = new Node(r, c);
}
if(map[r][c] != 'X') {
waterQ.offer(new Node(r, c));
}
}
}
// 출발점이 되는 백조
q.offer(swan[0]);
visited[swan[0].r][swan[0].c] = true;
int day = 0;
boolean meet = false;
while(true) {
Queue<Node> nextQ = new LinkedList<>();
while(!q.isEmpty()) {
Node now = q.poll();
// 백조를 만날시 종료
if(now.r == swan[1].r && now.c == swan[1].c) {
meet = true;
break;
}
for(int d = 0 ; d < 4 ; ++d) {
int nr = now.r + dir[d][0];
int nc = now.c + dir[d][1];
if(nr >= R || nr < 0 || nc >= C || nc < 0 || visited[nr][nc]) continue;
visited[nr][nc] = true;
// 물에 인접한 얼음으로 다음 날 백조가 탐색할 지역
if(map[nr][nc] == 'X') {
nextQ.offer(new Node(nr, nc));
continue;
}
// 현재 탐색 가능 지역
q.offer(new Node(nr, nc));
}
}
// 백조가 만났으면 종료
if(meet) break;
// q를 다음날 탐색할 지역이 담긴 nextQ로 바꾼다.
q = nextQ;
// 얼음을 녹인다.
int size = waterQ.size();
for(int i = 0 ; i < size ; ++i) {
Node now = waterQ.poll();
for(int d = 0 ; d < 4 ; ++d) {
int nr = now.r + dir[d][0];
int nc = now.c + dir[d][1];
if(nr >= R || nr < 0 || nc >= C || nc < 0) continue;
// 물에 인접한 얼음을 발견하면 녹이고 다시 큐에 넣는다.
if(map[nr][nc] == 'X') {
map[nr][nc] = '.';
waterQ.offer(new Node(nr, nc));
}
}
}
day++;
}
System.out.println(day);
}
}