baekjoon/Graph_Search
백준 4179번 : 불! [자바]
Meluu_
2025. 3. 19. 10:27
🧫 문제 분석
✔️ 출처
📖 문제

BFS로 풀 수 있는 문제로
문제에서 탈출구는 끝부분 즉, 행이 0이거나 열이 0 인 곳에 가기만 하면 탈출한다.
...
.J. //여기서는 8곳이 탈출구이다.
...
.##
.J# //여기서는 0,0, 1,0 이 탈출구이다.
###
또한 매 분마다 불이 퍼지고, 지훈이도 이동하는데
불을 먼저 이동시키고
지훈이를 이동시키면 된다.
불이 퍼졌을 때 불에 대한 방문 체크와 벽 체크
지훈이는 방문체크, 불과 벽 체크를 하면서 이동하면 된다.
분마다 퍼진 불들을 큐에 넣고
그 시간에 퍼진 불들만 퍼뜨려야한다.
아니면 시간과 상관없이 전부 퍼진다.
...
.F. // 0분 초기상태
...
.F. // 1분 전 1,1에 있는 불 하나가 퍼졌으므로 이 1개에 대한 불을 퍼뜨린다.
FFF // 1분 경과
.F.
FFF
FFF // 1분전 있는 0,1 1,0 2,1 2,1 에 있는 불만 퍼뜨린다.
FFF
🔅 문제 풀이
import java.io.*;
import java.util.*;
public class Main {
static int[] dy = {0, 0, 1, -1};
static int[] dx = {1, -1, 0, 0};
static boolean[][] visited;
static boolean[][] fireVisited;
static char[][] miro;
static int[] startPos;
static Queue<int[]> firePos = new LinkedList<>();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
int r = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
miro = new char[r][c];
visited = new boolean[r][c];
fireVisited = new boolean[r][c];
for (int i = 0; i < r; i++) {
String line = br.readLine();
for (int j = 0; j < c; j++) {
miro[i][j] = line.charAt(j);
if (miro[i][j] == 'J') {
startPos = new int[]{i, j};
}else if (miro[i][j] == 'F') {
firePos.add(new int[]{i, j});
fireVisited[i][j] = true;
// 벽은 방문표시로 갈 수 없게 만듦
}else if (miro[i][j] == '#') {
fireVisited[i][j] = true;
visited[i][j] = true;
}
}
}
int answer = bfs();
bw.write(answer == - 1 ? "IMPOSSIBLE" : answer + "");
bw.flush();
bw.close();
}
// 불 먼저 퍼트리고, 4가지 방향으로 이동
// 불이 지훈 옆이라면 지훈 자리를 F
private static int bfs() {
Queue<int[]> jihoonPosQueue = new LinkedList<>();
visited[startPos[0]][startPos[1]] = true;
jihoonPosQueue.add(startPos);
int time = 0;
while (!jihoonPosQueue.isEmpty()) {
fireBfs(); // 불 퍼뜨리기
int size = jihoonPosQueue.size();
time++;
// 1분 후 지훈이 이동 가능한 곳 이동
while (size--> 0) {
int[] curPos = jihoonPosQueue.poll();
// 탈출 가능하면 걸린 시간 반환
if (escapeCheck(curPos)) {
return time;
}
for (int i = 0; i < 4; i++) {
int nextR = curPos[0] + dy[i];
int nextC = curPos[1] + dx[i];
// 미로 범위를 넘어서는 지 확인, 방문했는지, 불인지 확인
if (boundaryCheck(nextR, nextC, miro)
|| visited[nextR][nextC]
|| miro[nextR][nextC] == 'F') continue;
jihoonPosQueue.add(new int[]{nextR, nextC});
visited[nextR][nextC] = true;
}
}
}
return -1;
}
// 불 이동
private static void fireBfs() {
int cnt = firePos.size();
// 현재 불들을 전파
while (cnt--> 0 && !firePos.isEmpty()) {
int[] fire = firePos.poll();
for (int i = 0; i < 4; i++) {
int newR = fire[0] + dy[i];
int newC = fire[1] + dx[i];
if (boundaryCheck(newR, newC, miro)
|| miro[newR][newC] == '#'
|| fireVisited[newR][newC]) continue;
miro[newR][newC] = 'F';
fireVisited[newR][newC] = true;
firePos.add(new int[]{newR, newC});
}
}
}
// 탈출 체크
private static boolean escapeCheck(int[] curPos) {
return curPos[0] == 0 || curPos[0] == miro.length - 1
|| curPos[1] == 0 || curPos[1] == miro[0].length - 1;
}
// 미로 범위 체크
private static boolean boundaryCheck(int newR, int newC, char[][] miro) {
return newR < 0 || newR >= miro.length
|| newC < 0 || newC >= miro[0].length;
}
}