[백준] 15683: 감시 - JAVA

https://www.acmicpc.net/problem/15683

풀이

cctv의 방향을 설정하여 사각지대를 최소로 만들어야 한다.

cctv의 종류는 5가지가 있다.

2번 cctv는 방향을 선택할 수 있는 방법이 2가지, 5번 cctv는 1가지였다.

나머지 cctv는 4방향 모두 선택할 수 있다.

입력받으면서 cctv의 위치를 저장했고, 그들의 방향을 저장할 배열을 만들어 각각 어떤 방향을 선택할지 조합을 만들었다.

조합이 완성되면 그 방향에 맞게 빈칸을 채워가면서 체크했다.

처음에 빈칸(0)의 개수를 세어놓고 빈칸을 몇개나 채웠는지를 세어 빼주면 된다.


메모리: 72084KB

시간: 304ms

언어: Java 11

코드

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

public class Main {
    static class Node {
        int r;
        int c;

        public Node(int r, int c) {
            this.r = r;
            this.c = c;
        }
    }

    static int N, M, zero, ans;
    static int[][] room, tmp;
    static List<Node> list;
    static int[] direction;

    // 오른쪽부터 시계방향
    static int[][] vector = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        room = new int[N][M];
        // 빈칸의 개수를 센다
        zero = 0;
        // cctv의 위치를 저장한다
        list = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < M; j++) {
                room[i][j] = Integer.parseInt(st.nextToken());
                if (room[i][j] == 0) {
                    zero++;
                } else if (room[i][j] < 6) {
                    list.add(new Node(i, j));
                }
            }
        }

        ans = Integer.MAX_VALUE;
        // cctv의 방향을 저장한다
        direction = new int[list.size()];
        makeDirection(0);

        System.out.println(ans);
    }

    private static void makeDirection(int idx) {
        if (idx == list.size()) {
            // 만들어진 방향 배열을 갖고 체크한다
            check();
            return;
        }

        Node node = list.get(idx);

        // 2번은 2방향, 5번은 1방향, 나머지는 4방향 선택 가능
        direction[idx] = 0;
        makeDirection(idx + 1);

        if (room[node.r][node.c] != 5) {
            direction[idx] = 1;
            makeDirection(idx + 1);
        }

        if (room[node.r][node.c] != 2 && room[node.r][node.c] != 5) {
            direction[idx] = 2;
            makeDirection(idx + 1);
            direction[idx] = 3;
            makeDirection(idx + 1);
        }
    }

    private static void check() {
        tmp = new int[N][M];
        for (int i = 0; i < N; i++) {
            tmp[i] = room[i].clone();
        }

        int cnt = 0;
        for (int i = 0; i < list.size(); i++) {
            Node node = list.get(i);
            int num = room[node.r][node.c];
            int dir = direction[i];

            // 방향에 맞게 빈칸을 채운다
            switch (num) {
                case 1:
                    cnt += cctv(dir, node.r, node.c);
                    break;
                case 2:
                    cnt += cctv(dir, node.r, node.c);
                    cnt += cctv(dir + 2, node.r, node.c);
                    break;
                case 3:
                    cnt += cctv(dir, node.r, node.c);
                    cnt += cctv((dir + 1) % 4, node.r, node.c);
                    break;
                case 4:
                    cnt += cctv(dir, node.r, node.c);
                    cnt += cctv((dir + 1) % 4, node.r, node.c);
                    cnt += cctv((dir + 2) % 4, node.r, node.c);
                    break;
                case 5:
                    cnt += cctv(dir, node.r, node.c);
                    cnt += cctv(dir + 1, node.r, node.c);
                    cnt += cctv(dir + 2, node.r, node.c);
                    cnt += cctv(dir + 3, node.r, node.c);
                    break;
            }
        }

        ans = Math.min(ans, zero - cnt);
    }

    private static int cctv(int type, int r, int c) {
        int result = 0;

        int nr = r;
        int nc = c;
        while (true) {
            nr += vector[type][0];
            nc += vector[type][1];

            if (nr < 0 || nc < 0 || nr >= N || nc >= M || tmp[nr][nc] == 6) {
                break;
            }
            if (tmp[nr][nc] == 0 && tmp[nr][nc] != -1) {
                result++;
                tmp[nr][nc] = -1;
            }
        }

        return result;
    }
}