https://www.acmicpc.net/problem/4179
4179번: 불!
입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다. 다음 입력으로 R줄동안 각각의 미로 행이 주어진다. 각각의 문자
www.acmicpc.net
[문제]
지훈이는 미로에서 일을 한다. 지훈이를 미로에서 탈출하도록 도와주자!
미로에서의 지훈이의 위치와 불이 붙은 위치를 감안해서 지훈이가 불에 타기전에 탈출할 수 있는지의 여부, 그리고 얼마나 빨리 탈출할 수 있는지를 결정해야한다.
지훈이와 불은 매 분마다 한칸씩 수평또는 수직으로(비스듬하게 이동하지 않는다) 이동한다.
불은 각 지점에서 네 방향으로 확산된다.
지훈이는 미로의 가장자리에 접한 공간에서 탈출할 수 있다.
지훈이와 불은 벽이 있는 공간은 통과하지 못한다.
[입력]
입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다.
다음 입력으로 R줄동안 각각의 미로 행이 주어진다.
각각의 문자들은 다음을 뜻한다.
- #: 벽
- .: 지나갈 수 있는 공간
- J: 지훈이의 미로에서의 초기위치 (지나갈 수 있는 공간)
- F: 불이 난 공간
J는 입력에서 하나만 주어진다.
[출력]
지훈이가 불이 도달하기 전에 미로를 탈출 할 수 없는 경우 IMPOSSIBLE 을 출력한다.
지훈이가 미로를 탈출할 수 있는 경우에는 가장 빠른 탈출시간을 출력한다.
[예제 입력 1]
4 4
####
#JF#
#..#
#..#
[예제 출력 1]
3
[내 풀이]
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.StringTokenizer;
/*
문제 : [G4] 불! - 4179번
결과 : 통과
성능 요약 : 메모리 48120KB, 시간 2864ms
아이디어 :
1. 전체 미로를 돌며 지훈이가 위치한 곳과 불이 위치한곳을 큐에 각각 넣어준다.
2. 큐에서 하나씩 위치정보를 빼면서 불을 먼저 이동시킨 후, 지훈이가 이동할 수 있으면 이동시키며 escapeTime을 1증가시킨다.
3. 더 이상 지훈이가 이동할 수 없을 때 까지 1~2를 반복한다.
4. 최종 탈출하는데 걸린 시간을 출력한다.
위 방식말고 불길이 가는 시간을 체크하며 모든 bfs를 다 돈 후
지훈이의 이동을 체크하면(불길이 가는 시간보다 빨리 움직일 경우 이동가능) 시간복잡도를 훨씬 많이 줄일 수 있을 것 같다...
*/
public class Main_4179_불 {
static int R, C, escapeTime;
static boolean isArrive;
static boolean[][] isJVisited;
static boolean[][] isFVisited;
static char[][] miro;
static int[][] dxdy = {{-1, 0}, {1, 0}, {0, -1}, { 0, 1}};
static Queue<int[]> qJ = new ArrayDeque<>();
static Queue<int[]> qF = new ArrayDeque<>();
static void bfs(int del, int row, int col) {
// 미로의 가장자리에 접한 공간에서 탈출 가능
if (del == 1 && (row == 0 || row == R - 1 || col == 0 || col == C - 1)) {
isArrive = true;
return;
}
for (int i = 0; i < 4; i++) {
int dx = row + dxdy[i][0];
int dy = col + dxdy[i][1];
if (dx >= 0 && dx < R && dy >= 0 && dy < C) {
// 불길
if (del == 2 && (miro[dx][dy] == '.' || miro[dx][dy] == 'J')) {
miro[dx][dy] = 'F';
}
// 지훈이
else if (del == 1 && miro[dx][dy] == '.') {
miro[dx][dy] = 'J';
}
}
}
}
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
R = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
miro = new char[R][C];
isJVisited = new boolean[R][C];
isFVisited = new boolean[R][C];
// 입력받은 문자열을 char형 2차원 배열로 변환
for (int i = 0; i < R; i++) {
st = new StringTokenizer(br.readLine());
miro[i] = st.nextToken().toCharArray();
}
// 더이상 지훈이가 이동할 수 없을 때까지 반복
boolean canMove = true;
while (canMove) {
canMove = false;
// 지훈이와 불 위치 체크
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
if (!isJVisited[i][j] && miro[i][j] == 'J') {
isJVisited[i][j] = true;
canMove = true;
qJ.offer(new int[]{i, j});
} else if (!isFVisited[i][j] && miro[i][j] == 'F') {
isFVisited[i][j] = true;
qF.offer(new int[]{i, j});
}
}
}
// <불보다 지훈이를 먼저 이동시키면 시간초과가 난다!>
// 불 이동 체크 (F's del == 2)
while (!qF.isEmpty()) {
int[] temp = qF.poll();
bfs(2, temp[0], temp[1]);
}
// 지훈이 이동 체크 (J's del == 1)
escapeTime += 1;
while (!qJ.isEmpty() && !isArrive) {
int[] temp = qJ.poll();
bfs(1, temp[0], temp[1]);
}
if (isArrive) break;
}
System.out.println(isArrive ? escapeTime : "IMPOSSIBLE");
}
}
<회고>
위 풀이대로 풀게 되면 매 반복마다 불길이 가는 구역과 지훈이가 가는 구역을 계산해야 하기 때문에 로직의 시간복잡도가 높다.
불길이 매 시간마다 가는 구역을 체크 한 후, 지훈이가 그 구역에 도달할 수 있는지 체크하여
반복없이 bfs만 돌아서 답을 구하게 되면 시간복잡도가 훨씬 작게 나올 것 같다.
'Algorithm > Java' 카테고리의 다른 글
[BOJ] 7576 : 토마토 [G5] (0) | 2024.03.09 |
---|---|
[BOJ] 10972 : 다음 순열 [S3] (1) | 2024.02.13 |
[SWEA] 1233. 사칙연산유효성검사 [D4] (1) | 2024.02.07 |
[BOJ] 3055 : 탈출 [G4] (1) | 2024.02.07 |
[BOJ] 13335번 : 트럭 [S1] (0) | 2024.02.04 |