백준
[백준 / JAVA] 4179. 불!
baefrica
2023. 8. 2. 01:36
반응형
https://www.acmicpc.net/problem/4179
4179번: 불!
입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다. 다음 입력으로 R줄동안 각각의 미로 행이 주어진다. 각각의 문자
www.acmicpc.net
💻 풀이 결과
💯 최종 코드
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class Node {
int r, c;
Node(int r, int c) {
this.r = r;
this.c = c;
}
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int R = sc.nextInt();
int C = sc.nextInt();
char[][] map = new char[R][C];
Queue<Node> fire = new LinkedList<>();
Queue<Node> jihoon = new LinkedList<>();
boolean[][] visited = new boolean[R][C];
for (int i = 0; i < R; i++) {
String str = sc.next();
for (int j = 0; j < C; j++) {
map[i][j] = str.charAt(j);
if (map[i][j] == 'F') {
fire.add(new Node(i, j));
}
if (map[i][j] == 'J') {
jihoon.add(new Node(i, j));
visited[i][j] = true;
}
}
}
int cnt = 0;
int[] dr = { 0, 0, -1, 1 };
int[] dc = { -1, 1, 0, 0 };
boolean isPossible = false;
// 지훈이가 가장자리로 갈 때까지
while (!jihoon.isEmpty()) {
// 매분마다 불이 확산된다.
int fireSize = fire.size();
for (int fs = 0; fs < fireSize; fs++) {
Node curr = fire.poll();
for (int d = 0; d < 4; d++) {
int nr = curr.r + dr[d];
int nc = curr.c + dc[d];
if (nr < 0 || nc < 0 || nr >= R || nc >= C) {
continue;
}
// 불이 퍼진 지점을 큐에 삽입
if (map[nr][nc] == '.') {
fire.add(new Node(nr, nc));
// 불 났다고 표시
map[nr][nc] = 'F';
}
}
} // 불 퍼지는 것 끝
int size = jihoon.size();
cnt++;
for (int s = 0; s < size; s++) {
Node curr = jihoon.poll();
// 종료 조건
if (curr.r == 0 || curr.r == R - 1 || curr.c == 0 || curr.c == C - 1) {
isPossible = true;
jihoon.clear();
break;
}
for (int d = 0; d < 4; d++) {
int nr = curr.r + dr[d];
int nc = curr.c + dc[d];
if (nr < 0 || nc < 0 || nr >= R || nc >= C) {
continue;
}
if (visited[nr][nc]) {
continue;
}
// 이동할 수 있는 지점을 큐에 삽입
if (map[nr][nc] == '.') {
jihoon.add(new Node(nr, nc));
visited[nr][nc] = true;
map[curr.r][curr.c] = '.';
}
}
}
}
if (isPossible) {
System.out.println(cnt);
} else {
System.out.println("IMPOSSIBLE");
}
}
}
💢 틀린 이유
1. 메모리 초과
- 지훈이의 위치 노드를 담는 큐에서 메모리 초과가 발생한 것을 발견하였다.
- 메모리 초과가 발생한 이유는 지훈이 위치를 큐에 담을 때 방문처리를 하지 않아서 계속해서 다음 갈 수 있는 위치들이 큐에 담기는 로직이었기 때문이다.
- visited 배열을 만들어 지훈이 위치에 대해 방문 처리를 해줘서 해결하였다.
2. 불의 확산 vs 지훈이의 이동
- 처음 구현한 로직은 불의 확산과 지훈이의 이동의 순서를 고려하지 않았다.
- 생각해 보니 사건은 동시에 일어나기 때문에, 불을 먼저 확산시키고 불이 퍼진 자리는 지훈이가 이동하지 못하도록 처리하였다.
💬 풀이 과정
- BFS 큰 틀은 지훈이 위치에 대한 큐가 비었을 때 종료하도록 하였다.
- 불이 난 자리들의 위치와 지훈이의 위치를 각각 큐에 삽입한 채로 시작하였다.
- 1초 단위로 일어나는 일들을 순서대로 구현한다는 생각으로, 불들을 확산시키고 지훈이를 이동시켰다.
- 4방 탐색을 통해 불을 확산시키고 불이 퍼진 자리를 처리하였다.
- 불이 한번 퍼질 때마다 지훈이를 한번 이동시키고 방문처리하였다.
- 지훈이 위치를 꺼냈을 때 탈출할 수 있는 지점이라면 큐를 비워 즉시 종료되도록 하였다.
💡 깨달은 점
1. BFS 응용 - 시작점이 두 종류일 때
- 두 시작점에 대한 각각의 BFS를 돌린다.
- 두 BFS에 대한 처리 순서를 신경 써야 한다.
- 두 BFS가 서로 영향을 주는 문제의 경우에는 이러한 로직으로 풀 수가 없다. 그래서 시간 순으로 동시에 진행시켜야 한다. (백트래킹 기법 사용 필요)
반응형