[JAVA/14502번] 연구소

고지훈·2021년 10월 19일
1

Algorithm

목록 보기
41/68
post-thumbnail

문제


입력 및 출력


풀이

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

class Main {
    public static int N;
    public static int M;
    public static int[] dx = {0, 0, -1, 1};
    public static int[] dy = {1, -1, 0, 0};
    public static int[][] map;
    public static int result = Integer.MIN_VALUE;

    public static void main(String args[]) throws Exception {
        // 바이러스를 막을 수 있는 경우 => 세로, 가로, 대각선
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // 세로크기 N, 가로크기 M
        String[] temp = br.readLine().split(" ");
        N = Integer.parseInt(temp[0]);
        M = Integer.parseInt(temp[1]);

        // 지도, 벽을 위한 지도
        map = new int[N][M];

        // 지도 데이터 입력
        for (int i = 0; i < N; i++) {
            temp = br.readLine().split(" ");
            for (int j = 0; j < temp.length; j++) {
                map[i][j] = Integer.parseInt(temp[j]);
            }
        }

        // 벽을 세우고 바이러스 퍼지게하기
        makeWall(0);

        // 결과 출력
        System.out.println(result);
    }

    // 벽 세우기
    public static void makeWall(int depth) {
        // 벽은 세개까지 세울 수 있기 때문에
        if (depth == 3) {
            BFS();
            return;
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                // 빈칸일 경우 벽을 세우고 재귀함수 호출
                if (map[i][j] == 0) {
                    map[i][j] = 1;
                    makeWall(depth + 1);
                    map[i][j] = 0;
                }
            }
        }
    }

    public static void BFS() {
        int[][] virus_map = new int[N][M];

        // virus타입을 갖는 큐 선언
        Queue < Virus > queue = new LinkedList < > ();

        // virus_map에 벽을 세운 map을 복사
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                virus_map[i][j] = map[i][j];
            }
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                // 해당 자리가 바이러스일 경우 큐에 넣는다.
                if (virus_map[i][j] == 2) {
                    queue.add(new Virus(i, j));
                }
            }
        }

        while (!queue.isEmpty()) {
            Virus virus = queue.poll();

            // 이동할 수 있는 방향은 총 4가지(상, 하, 좌, 우)
            for (int i = 0; i < 4; i++) {
                int nx = virus.x + dx[i];
                int ny = virus.y + dy[i];

                // 범위안에 있고, 해당 자리가 빈칸일 경우 바이러스로 변경
                if (isRange(nx, ny)) {
                    if (virus_map[nx][ny] == 0) {
                        virus_map[nx][ny] = 2;
                        queue.add(new Virus(nx, ny));
                    }
                }
            }
        }

        int count = 0;

        // 안전지역 계산을 위한 반복문
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (virus_map[i][j] == 0) {
                    count++;
                }
            }
        }

        // 둘 중 더 큰 값을 result에 저장한다.
        result = Math.max(count, result);

    }

    public static boolean isRange(int x, int y) {
        if (x >= 0 && y >= 0 && x < N && y < M) {
            return true;
        }
        return false;
    }
}

class Virus {
    // x축, y축
    int x, y;

    public Virus(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

결과 및 해결방법

[결과]

[정리]

해결방법
이전에 연산자 끼워넣기와 데스 나이트를 풀었다면 해결할 수 있는 문제였다.

makeWall()의 경우, DFS를 기반으로 코드를 구성하였다. 문제에서 벽은 총 3개까지만 세울 수 있으므로 depth가 3이될 때 BFS()를 호출한다.
모든 경우의 수를 구해야하므로 이중 반복문을 통해 해당 인덱스가 0일 경우 벽을 세우고 makeWall()을 다시 호출하였다. 그 후, 다음 반복문을 위해 해당 인덱스를 다시 초기화해주었다.

BFS()의 경우, 이전에 풀었던 데스 나이트 문제를 기반으로 코드를 구성하였다.
virus_map변수는 BFS()가 호출된 시점의 맵 상태를 가져와야하기 때문에 반복문을 통해 맵의 정보를 복사해주었다. 이때, virus_map = map과 같은 방법은 얕은 복사이기 때문에 정보가 복사되지 않는다는 것을 알았다.

그 이후의 과정은 벽으로 막혀있는 부분을 제외한 나머지 부분을 바이러스가 감염시키는 과정으로 큐에 가장 앞에 있는 바이러스를 뽑은 후 해당 바이러스의 상, 하, 좌, 우로 빈칸일 경우 감염시켜주었다.

모든 과정이 끝난 후, 반복문을 돌리며 인덱스가 0인 부분에 대해 count값을 1증가시켜주었고, 안전지대가 제일 많은 것을 저장해야하기 때문에 비교를 통하여 result변수에 저장해주었다.

profile
"계획에 따르기보다 변화에 대응하기를"

0개의 댓글