Algorithm/Graph Search Algorithm
BOJ G4 4179 불! JAVA
rueMi
2023. 7. 13. 23:47
4179번: 불!
입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다. 다음 입력으로 R줄동안 각각의 미로 행이 주어진다. 각각의 문자
www.acmicpc.net
문제 읽기
문제를 처음 읽었을 땐 별 문제 없이 구현할 수 있을 줄 알았지만.. 자잘한 실수와 문제를 제대로 읽지 않은 게 원인이 되어 조금 헤맸다.
문제 해결
자료구조
char[][] map
Queue 두 개
- 지훈이 이동 Q
- 불 이동 Q
실수한 부분
불 퍼지는 방식 이상하게 함
- 처음에는 이상하게 생각해서 지훈이 큐랑 불 큐랑 두 개 만들고 지훈이 큐에서 하나씩 뺄 때마다 불 큐에서도 하나 빼서 상하좌우 이동함. 결국 depth 다 꼬여서 답 안 나옴
- 불 퍼지는 걸 for문 + 이차원 배열 복사를 통해서 구현함. 답은 나올 거 같았지만 2퍼센트에서 시간초과가 나옴
- 불 큐를 다시 부활시키고, 지훈이 큐에서 depth가 바뀔 때마다 불 큐에서 해당 depth의 불만 퍼지게 함. 이때 마지막에 꺼낸 불은 다시 넣어줘야 함!
입력 제대로 체크 안 함
불이 여러 군데에서 들어오는 걸 질문 게시판에서 반례 찾아보면서 알았다.. 이거 해결하니까 11퍼에서 정답으로 나옴
코드
package ps.ㄱSolving;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Queue;
public class BOJ_G4_4179_불 {
static class Pos{
int r, c;
int depth;
public Pos(int r, int c, int depth) {
super();
this.r = r;
this.c = c;
this.depth = depth;
}
@Override
public String toString() {
return "Pos [r=" + r + ", c=" + c + ", depth=" + depth + "]";
}
}
static char[][] map;
static int R, C;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String[] line = in.readLine().split(" ");
R = Integer.parseInt(line[0]);
C = Integer.parseInt(line[1]);
Queue<Pos> fq = new ArrayDeque<>();
Pos start = null;
map = new char[R][C];
for (int i = 0; i < R; i++) {
map[i] = in.readLine().toCharArray();
for (int j = 0; j < C; j++) {
if (map[i][j] == 'J') {
start = new Pos(i, j, 0);
map[i][j] = '.'; //빈칸임
}
else if (map[i][j] == 'F') {
fq.offer(new Pos(i, j, 0));
}
}
}
//logic : bfs : 지훈이, 불 각각 큐에 넣고..
/*
* 지훈이는 상하좌우로 이동하고 (. 이동 가능, #, F 이동 불가)
* 불은 상하좌우로 퍼지고 (. 이동 가능, # 이동 불가)
*/
boolean[][] visitedJ = new boolean[R][C];
Queue<Pos> jq = new ArrayDeque<>();
jq.offer(start);
visitedJ[start.r][start.c] = true;
int[] dr = {-1, 1, 0, 0};
int[] dc = {0, 0, -1, 1};
int saveDepth = -1;
while(!jq.isEmpty()) {
//지훈이는 상하좌우로 이동
Pos curJ = jq.poll();
if (saveDepth != curJ.depth) {
//불은 상하좌우로 퍼짐
saveDepth = curJ.depth;
while(!fq.isEmpty()) {
Pos curF = fq.poll();
if (saveDepth != curF.depth) {
fq.offer(curF); //뺐으니까 다시 넣기..
break;
}
for (int di = 0; di < 4; di++) {
int nr = curF.r + dr[di];
int nc = curF.c + dc[di];
if (nr < 0 || nr >= R || nc < 0 || nc >= C) {
continue;
}
else if (map[nr][nc] == '.') {
//빈칸일 때만 갈 수 있음
map[nr][nc] = 'F';
fq.offer(new Pos(nr, nc, curF.depth+1));
}
}
}
}
for (int di = 0; di < 4; di++) {
int nr = curJ.r + dr[di];
int nc = curJ.c + dc[di];
//인덱스 초과하면 종료
if (nr < 0 || nr >= R || nc < 0 || nc >= C) {
System.out.println(curJ.depth+1);
System.exit(0);
}
else if (map[nr][nc] == '.' && !visitedJ[nr][nc]) {
//불이나 벽이 없으면 이동 가능 -> .이면 이동 가능
visitedJ[nr][nc] = true;
jq.offer(new Pos(nr, nc, curJ.depth + 1));
}
}
}
System.out.println("IMPOSSIBLE");
}
}