4 minute read


0. 들어가면서

불! 문제이다.
시작점이 여러가지인 문제이다.
BFS문제이다.

1. Java

1.1 내가 푼 코드

package bj.ch09_bfs;

import java.util.*;
import java.io.*;

public class BJ_4179_불_01 {
    /*
     * r*c = 1000000 이므로 대략 NlogN안에 끝내야 한다.
     * 지훈, 불 각각의 큐를 사용한다.
     * 지훈이는 불이 난 곳으로 이동할 수 없기 때문에 불 먼저 돌린다.
     * 지훈이는 거리까지 알아야한다.
     * 4 4
     * ####
     * #JF#
     * #..#
     * #..#
     */
    static Queue<int[]> fQ = new LinkedList<>();
    static Queue<int[]> jQ = new LinkedList<>();
    static char[][] map;
    static int[][] dist;
    static int R, C;

    static int[] dy = { -1, 1, 0, 0 }; // 상하좌우
    static int[] dx = { 0, 0, -1, 1 };

    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());

        map = new char[R][C];
        dist = new int[R][C];

        for (int y = 0; y < R; y++) {
            String line = br.readLine();
            for (int x = 0; x < C; x++) {
                char c = line.charAt(x);
                map[y][x] = c;
                dist[y][x] = -1;
                if (c == 'J') {
                    jQ.offer(new int[] { y, x });
                    dist[y][x] = 0;
                }
                if (c == 'F') {
                    fQ.offer(new int[] { y, x });
                }
            }
        }

        while (!jQ.isEmpty()) {
            // 불 먼저 돌린다.
            int fSize = fQ.size();
            for (int fs = 0; fs < fSize; fs++) {
                int[] curF = fQ.poll();
                for (int d = 0; d < 4; d++) {
                    int nFy = curF[0] + dy[d];
                    int nFx = curF[1] + dx[d];
                    if (nIR(nFy, R) || nIR(nFx, C)) // 범위 초과
                        continue;
                    if (map[nFy][nFx] == '#') // 벽
                        continue;
                    if (map[nFy][nFx] == 'F') // 이미 불
                        continue;
                    map[nFy][nFx] = 'F'; // 불이 번져
                    fQ.offer(new int[] { nFy, nFx });
                }
            }
            // 지훈이 차례
            int jSize = jQ.size();
            for (int js = 0; js < jSize; js++) {
                int[] curJ = jQ.poll();
                for (int d = 0; d < 4; d++) {
                    int nJy = curJ[0] + dy[d];
                    int nJx = curJ[1] + dx[d];
                    if (nIR(nJy, R) || nIR(nJx, C)) { // 범위 초과
                        System.out.println(dist[curJ[0]][curJ[1]] + 1);
                        return;
                    }
                    if (map[nJy][nJx] == '#') { // 벽
                        continue;
                    }
                    if (map[nJy][nJx] == 'F') { // 불
                        continue;
                    }
                    if (dist[nJy][nJx] >= 0) { // 이미 방문
                        continue;
                    }
                    dist[nJy][nJx] = dist[curJ[0]][curJ[1]] + 1;
                    jQ.offer(new int[] { nJy, nJx });
                }
            }
        }
        System.out.println("IMPOSSIBLE");
    }

    private static boolean nIR(int v, int range) {
        return (v < 0 || v >= range) ? true : false;
    }
}


1.3 바킹독을 참고한 코드

package bj.ch09_bfs;

import java.util.*;
import java.io.*;

public class BJ_4179_불_01_BarkingDog {
    /*
     * r*c = 1000000 이므로 대략 NlogN안에 끝내야 한다.
     * 지훈, 불 각각의 큐를 사용한다.
     * 지훈이는 불이 난 곳으로 이동할 수 없기 때문에 불 먼저 돌린다.
     * 지훈이는 거리까지 알아야한다.
     * 4 4
     * ####
     * #JF#
     * #..#
     * #..#
     */
    static Queue<int[]> fQ = new LinkedList<>();
    static Queue<int[]> jQ = new LinkedList<>();
    static char[][] map;
    static int[][] distF;
    static int[][] distJ;
    static int R, C;

    static int[] dy = { -1, 1, 0, 0 }; // 상하좌우
    static int[] dx = { 0, 0, -1, 1 };

    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());

        map = new char[R][C];
        distF = new int[R][C];
        distJ = new int[R][C];

        for (int y = 0; y < R; y++) {
            String line = br.readLine();
            for (int x = 0; x < C; x++) {
                char c = line.charAt(x);
                map[y][x] = c;
                distF[y][x] = -1;
                distJ[y][x] = -1;
                if (c == 'J') {
                    jQ.offer(new int[] { y, x });
                    distJ[y][x] = 0;
                }
                if (c == 'F') {
                    fQ.offer(new int[] { y, x });
                    distJ[y][x] = 0;
                }
            }
        }

        while (!fQ.isEmpty()) {
            int[] curF = fQ.poll();
            for (int d = 0; d < 4; d++) {
                int nFy = curF[0] + dy[d];
                int nFx = curF[1] + dx[d];
                if (nIR(nFy, R) || nIR(nFx, C)) // 범위 초과
                    continue;
                if (map[nFy][nFx] == '#' || distF[nFy][nFx] >= 0) // 벽 이거나 불이 번졌거나
                    continue;
                distF[nFy][nFx] = distF[curF[0]][curF[1]] + 1;
                fQ.offer(new int[] { nFy, nFx });
            }
        }
        // 불 다 번졌고 얼마만에 번지는지도 계산이 끝난 상태
        // 즉, 지훈이는 불이 번지는 시간을 알고있다.
        // 지훈이는 불이 번지는 시간보다 빨리 도착해야한다.
        while (!jQ.isEmpty()) {
            int[] curJ = jQ.poll();
            for (int d = 0; d < 4; d++) {
                int nJy = curJ[0] + dy[d];
                int nJx = curJ[1] + dx[d];
                if (nIR(nJy, R) || nIR(nJx, C)) { // 범위 초과, 즉 탈출이다!
                    System.out.println(distJ[curJ[0]][curJ[1]] + 1);
                    return;
                }
                if (map[nJy][nJx] == '#' || distJ[nJy][nJx] >= 0) // 벽 이거나 이미 방문했거나
                    continue;
                if (distF[nJy][nJx] != -1 && distF[nJy][nJx] <= distJ[curJ[0]][curJ[1]] + 1) // 불이 번지는 시간이 지훈이가 도착하는
                                                                                             // 시간보다 빠르면
                    continue;
                distJ[nJy][nJx] = distJ[curJ[0]][curJ[1]] + 1;
                jQ.offer(new int[] { nJy, nJx });
            }
        }
        System.out.println("IMPOSSIBLE"); // 탈출 불가능
    }

    private static boolean nIR(int v, int range) {
        return (v < 0 || v >= range) ? true : false;
    }
}

1.4 해설

  • 시작점이 여러개이고, 거리를 구해야하는 문제이다.
  • 불을 먼저 퍼뜨리고, 지훈이를 퍼뜨린다.
  • 이 과정에서 불필요한 변수를 줄일 수 있지 않을까?
  • 좀 더 빨리 반복문을 빠져나올 수 있지 않을까에 대해서 생각해보았다.
  • 바킹독
    • 방문이나, 거리에대한 dist를 써주고, 반복문안에 반복문을 없앴다.
    • 나는 불번지고 지훈이 가고 불번지고 지훈이 가고 이런식으로 했는데
    • 바킹독은 불 모두 번지고 시간 기록하고
    • 지훈이 모두 이동하고 시간 기록하고 이런식으로 했다.

2. Go

CLOSING

재활훈련 필요, 멀었다.

Leave a comment