https://www.acmicpc.net/problem/5427

이 문제는 그래프 탐색 문제로, 상근이와 불의 이동을 동시에 처리해야 합니다. 상근이가 건물에서 가장 빠르게 탈출할 수 있는 시간을 구하는 문제입니다. 불은 매 초마다 확산되기 때문에, 불이 퍼지기 전에 상근이가 탈출해야 합니다. 만약 불이 먼저 도달하거나 탈출할 방법이 없으면 "IMPOSSIBLE"을 출력해야 합니다.
import java.util.*;
import java.io.*;
public class Main {
static int w, h;
static char[][] building;
static int[][] fireTime; // 불이 도착하는 시간
static int[][] personTime; // 상근이가 도착하는 시간
static Queue<int[]> fireQueue; // 불의 위치를 저장하는 큐
static Queue<int[]> personQueue; // 상근이의 위치를 저장하는 큐
// 상, 하, 좌, 우 이동을 위한 방향 벡터
static int[] dx = {0, 0, -1, 1};
static int[] dy = {-1, 1, 0, 0};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int T = Integer.parseInt(br.readLine()); // 테스트 케이스 개수
while (T-- > 0) {
st = new StringTokenizer(br.readLine());
w = Integer.parseInt(st.nextToken()); // 빌딩의 너비
h = Integer.parseInt(st.nextToken()); // 빌딩의 높이
building = new char[h][w];
fireTime = new int[h][w]; // 불이 해당 칸에 도착하는 시간
personTime = new int[h][w]; // 상근이가 해당 칸에 도착하는 시간
fireQueue = new LinkedList<>();
personQueue = new LinkedList<>();
// 배열 초기화
for (int i = 0; i < h; i++) {
Arrays.fill(fireTime[i], -1); // 불 도착 시간을 -1로 초기화
Arrays.fill(personTime[i], -1); // 상근이 도착 시간을 -1로 초기화
}
// 입력 처리
for (int i = 0; i < h; i++) {
String line = br.readLine();
for (int j = 0; j < w; j++) {
building[i][j] = line.charAt(j);
if (building[i][j] == '*') { // 불이 시작되는 위치
fireQueue.offer(new int[]{i, j});
fireTime[i][j] = 0; // 불이 있는 칸의 도착 시간을 0으로 설정
} else if (building[i][j] == '@') { // 상근이의 시작 위치
personQueue.offer(new int[]{i, j});
personTime[i][j] = 0; // 상근이의 시작 시간도 0으로 설정
}
}
}
// 불의 확산 BFS
spreadFire();
// 상근이의 이동 BFS
int result = movePerson();
// 결과 출력
if (result == -1) {
System.out.println("IMPOSSIBLE");
} else {
System.out.println(result);
}
}
}
// 불의 확산을 처리하는 BFS
static void spreadFire() {
while (!fireQueue.isEmpty()) {
int[] cur = fireQueue.poll();
int x = cur[0];
int y = cur[1];
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < h && ny >= 0 && ny < w) {
if (building[nx][ny] == '.' && fireTime[nx][ny] == -1) {
fireTime[nx][ny] = fireTime[x][y] + 1;
fireQueue.offer(new int[]{nx, ny});
}
}
}
}
}
// 상근이의 이동을 처리하는 BFS
static int movePerson() {
while (!personQueue.isEmpty()) {
int[] cur = personQueue.poll();
int x = cur[0];
int y = cur[1];
// 상근이가 경계에 도착하면 탈출 성공
if (x == 0 || x == h - 1 || y == 0 || y == w - 1) {
return personTime[x][y] + 1; // 경계에서 탈출하므로 +1초
}
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < h && ny >= 0 && ny < w) {
if (building[nx][ny] == '.' && personTime[nx][ny] == -1) {
// 불이 도착하는 시간보다 먼저 이동할 수 있어야 함
if (fireTime[nx][ny] == -1 || fireTime[nx][ny] > personTime[x][y] + 1) {
personTime[nx][ny] = personTime[x][y] + 1;
personQueue.offer(new int[]{nx, ny});
}
}
}
}
}
return -1; // 탈출할 수 없는 경우
}
}
h, 너비 w 및 빌딩의 지도 정보를 입력받습니다.building[][], fireTime[][], personTime[][] 배열을 초기화하고, 불(`)과 상근이(@`)의 위치를 큐에 추가합니다.spreadFire() 함수는 불이 확산되는 과정을 BFS로 처리합니다. 각 불이 인접한 칸으로 확산되며, 해당 칸에 도착하는 시간을 기록합니다.'#')이나 이미 확산된 곳은 확산하지 않습니다.movePerson() 함수는 상근이의 이동을 BFS로 처리합니다. 상근이는 빈 공간(.)으로만 이동할 수 있으며, 불이 도착하는 시간보다 먼저 해당 칸에 도착할 수 있어야 합니다.1을 반환합니다.personTime)과 불이 그 칸에 도착하는 시간(fireTime)을 비교하여, 상근이가 불보다 먼저 도착할 수 있을 때만 이동이 가능합니다.