#
, .
, J
, F
문자가 주어짐IMPOSSIBLE
출력BFS로 풀 수 있는 문제이다.
기존에 한 가지 요소만 이동하는 BFS 문제와 달리,동시에 두 가지 요소의 BFS를 수행해야 한다.
- 불은 상, 하, 좌, 우로 이동할 수 있고 지훈이가 있는 위치로도 이동할 수 있다.
- 지훈이와 불은 동시에 이동하므로, 지훈이는 동일한 시간에 불이 도달하는 위치를 피해가도록 해야한다.
따라서, 불을 먼저 이동하게 한 후, 갱신된 미로 상태에 따라 지훈이의 이동 경로를 설정한다.
변수 & 클래스 선언
private static char[][] map;
private static Queue<int[]> fire = new ArrayDeque<>();
private static Queue<Person> person = new ArrayDeque<>();
private static int[] dx = new int[]{0, 1, 0, -1};
private static int[] dy = new int[]{1, 0, -1, 0};
public static class Person {
int x, y, count;
public Person(int x, int y, int count) {
this.x = x;
this.y = y;
this.count = count;
}
}
...
map
: 미로 상태 저장
fire
, person
큐: 각각 불의 위치, 지훈이의 위치를 저장
dx
, dy
: 상, 하, 좌, 우 이동에 사용하는 변수
Person 클래스
: 지훈이 위치 및 소요 시간
미로 상태 입력 받기
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int row = Integer.parseInt(st.nextToken());
int col = Integer.parseInt(st.nextToken());
map = new char[row][col];
for (int i = 0; i < row; i++) {
String str = br.readLine();
for (int j = 0; j < str.length(); j++) {
map[i][j] = str.charAt(j);
if (map[i][j] == 'J')
person.offer(new Person(i, j, 1));
else if (map[i][j] == 'F')
fire.offer(new int[]{i, j});
}
}
// bfs 호출
int res = p_bfs();
if(res == -1) System.out.println("IMPOSSIBLE");
else System.out.println(res);
...
BFS 수행
private static int p_bfs() {
// 지훈이가 이동할 곳이 없을 때까지 반복
while (!person.isEmpty()) {
// 현재 큐에 존재하는 불 개수
int f_len = fire.size();
int i=0;
// 큐에 존재하는 불 개수만큼 반복
while(i<f_len) {
int[] c_fire = fire.poll();
for (int d = 0; d < 4; d++) {
int fx = c_fire[0] + dx[d];
int fy = c_fire[1] + dy[d];
// 불 이동
if (fx >= 0 && fy >= 0 && fx < map.length && fy < map[0].length) {
if (map[fx][fy] == '.') {
map[fx][fy] = 'F'; // 미로 갱신
fire.offer(new int[]{fx, fy}); // 새로운 불의 위치 저장
}
}
}
i++;
}
i=0;
int p_len = person.size();
// 현재 큐에 있는 지훈이 위치 개수 만큼 반복
while(i<p_len) {
Person simon = person.poll();
// 지훈이의 현재 위치가 탈출 가능한 위치인 경우
if(simon.x == 0 || simon.x ==map.length-1 ||
simon.y==0 || simon.y == map[0].length-1)
return simon.count; // 소요시간 반환 및 종료
for (int d = 0; d < 4; d++) {
int px = simon.x + dx[d];
int py = simon.y + dy[d];
if (px >= 0 && py >= 0 && px < map.length && py < map[0].length) {
// 다음 위치가 탈출 가능한 위치인 경우
if (px == 0 || px == map.length - 1 || py == 0 || py == map[0].length) {
if(map[px][py]!='#' && map[px][py]!='F')
return simon.count+1; // 소요시간 반환 및 종료
}
if (map[px][py] == '.') {
map[px][py] = 'J'; // 방문 처리
person.offer(new Person(px, py, simon.count + 1)); // 갱신된 지훈이 위치 저장
}
}
}
i++;
}
}
return -1; // 탈출할 수 없는 경우
}
px, py
)가 탈출 가능한 위치인 경우 소요시간 +1 반환-1
반환package Algorithm.BFS;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.StringTokenizer;
public class N_4179 {
private static char[][] map;
private static Queue<int[]> fire = new ArrayDeque<>();
private static Queue<Person> person = new ArrayDeque<>();
private static int[] dx = new int[]{0, 1, 0, -1};
private static int[] dy = new int[]{1, 0, -1, 0};
public static class Person {
int x, y, count;
public Person(int x, int y, int count) {
this.x = x;
this.y = y;
this.count = count;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int row = Integer.parseInt(st.nextToken());
int col = Integer.parseInt(st.nextToken());
map = new char[row][col];
for (int i = 0; i < row; i++) {
String str = br.readLine();
for (int j = 0; j < str.length(); j++) {
map[i][j] = str.charAt(j);
if (map[i][j] == 'J')
person.offer(new Person(i, j, 1));
else if (map[i][j] == 'F')
fire.offer(new int[]{i, j});
}
}
int res = p_bfs();
if(res == -1) System.out.println("IMPOSSIBLE");
else System.out.println(res);
}
private static int p_bfs() {
while (!person.isEmpty()) {
int f_len = fire.size();
int i=0;
while(i<f_len) {
int[] c_fire = fire.poll();
for (int d = 0; d < 4; d++) {
int fx = c_fire[0] + dx[d];
int fy = c_fire[1] + dy[d];
// 불 이동
if (fx >= 0 && fy >= 0 && fx < map.length && fy < map[0].length) {
if (map[fx][fy] == '.') {
map[fx][fy] = 'F'; // 방문 처리
fire.offer(new int[]{fx, fy}); // 다음 이동
}
}
}
i++;
}
i=0;
int p_len = person.size();
while(i<p_len) {
Person simon = person.poll();
if(simon.x == 0 || simon.x ==map.length-1 ||
simon.y==0 || simon.y == map[0].length-1)
return simon.count;
for (int d = 0; d < 4; d++) {
int px = simon.x + dx[d];
int py = simon.y + dy[d];
if (px >= 0 && py >= 0 && px < map.length && py < map[0].length) {
// 탈출이 가능 지점에 있는 경우
if (px == 0 || px == map.length - 1 || py == 0 || py == map[0].length) {
if(map[px][py]!='#' && map[px][py]!='F')
return simon.count+1;
}
if (map[px][py] == '.') {
map[px][py] = 'J'; // 방문 처리
person.offer(new Person(px, py, simon.count + 1)); // 다음 이동
}
}
}
i++;
}
}
return -1;
}
}
지훈이가 동시에 이동함을 고려하는 부분에서 오래걸렸다.
동시 라는 조건에 묶여서 p_bfs(지훈 이동), f_bfs(불 이동) 이렇게 두 함수를 작성해서 f_bfs 수행 도중 J를 만나면 p_bfs를 호출하는 로직으로 가볼까 했지만, 더 복잡해지는 것 같았다.
두 번째는 불이 이동하다가, 지훈이를 만나면 IMPOSSIBLE을 뱉도록 할까 했지만, 내 코드에서 방문 처리를 J
, F
로 했기에 지훈이의 잔상을 만나는 경우가 있어서 취소했다.
마지막으로 현재 불을 먼저 이동시키고, 갱신된 미로 상태에 따라 지훈이를 이동시키도록 했다.
탈출 조건
1. 미로의 초기 상태에서 지훈이의 현 위치가 탈출 가능한 위치인 경우
2. 다음 위치가 탈출 가능한 위치지만#
과F
가 아닌 경우
이 문제에 투자한 시간은 약 5시간 정도 되는 듯하다.
오래 걸리니 오기로 혼자 풀어보려고 노력했다.
시간 단축은 많이 풀어보는 수밖에 없다. 파이팅!