포스트

[백준][15683] 감시

이 포스트는 백준 사이트의 감시 문제 풀이입니다.

문제

문제


해결 과정

이 문제에서 핵심은 CCTV 회전과 그에 따른 사각지대 개수입니다.

이 문제를 해결하고자 먼저 CCTV 의 방향을 어떻게 구현할지 고민 중
기존에 사용하는 방법인 dir_row, dir_col 배열을 활용해보기로 했습니다.

5가지의 CCTV 는 각각 4가지 방향 중 최대 4개만 사용하므로
2차원 벡터를 활용하여 CCTV 가 감시하는 방향을 표현하였습니다.(변수명: cctv_type)
방향 표시는 위에서 언급한 dir_row, dir_col 에서 각 원소가 상(인덱스: 0), 우(1), 하(2), 좌(3) 순서이므로
문제에서 제시된 각 CCTV 의 현재 방향을 0으로 생각하고
0, 1, 2, 3 을 사용해 cctv_type 의 각 방향 정보를 저장하였습니다.

마지막으로 CCTV 를 회전시키기 위해서

1
((현재방향(0~3)) + (CCTV 회전방향(0~3))) % 4

위 수식을 사용해서 새로운 방향에 따라 감시되는 영역을 구하고
CCTV 개수와 벽 개수를 제외한 빈 공간 수 total_area에서
감시되는 영역을 뺸 값인 hidden_area 를 출력하였습니다.


코드 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <vector>

using namespace std;

// 12시 방향에서 시계방향 순서대로 4가지 방향
int dir_row[4]{ -1, 0, 1, 0 };
int dir_col[4]{ 0, 1, 0, -1 };

int total_area, hidden_area = 2e9;

// 행, 열, cctv 타입, 회전 방향
struct POINT {
    int row, col, type, dir;
};

int N, M;
vector<vector<int>> board;

// 1번부터 5번까지 cctv의 감시 방향
vector<vector<int>> cctv_type{
    {},
    {1},
    {1, 3},
    {0, 1},
    {0, 1, 3},
    {0, 1, 2, 3}
};

void input(vector<POINT>& cctv);
void set_watching_area(vector<POINT>& cctv,
    vector<vector<bool>>& visited, POINT& camera);
int count_hidden_area(vector<POINT>& cctv);
void DFS(vector<POINT> cctv, int curr);

int main() {
    vector<POINT> cctv;
    input(cctv);

    DFS(cctv, 0);

    printf("%d", hidden_area);

    return 0;
}

void input(vector<POINT>& cctv) {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> N >> M;
    board.assign(N, vector<int>(M, 0));
    for (int row = 0; row < N; ++row) {
        for (int col = 0; col < M; ++col) {
            cin >> board[row][col];
            if (board[row][col] != 0
                && board[row][col] != 6) {
                cctv.push_back({ row, col, board[row][col], 0 });
            }
            if (board[row][col] == 0) {
                total_area += 1;
            }
        }
    }
}

void DFS(vector<POINT> cctv, int curr) {
    if (curr == cctv.size()) {
        hidden_area = min(hidden_area, count_hidden_area(cctv));
        return;
    }

    if(cctv[curr].type == 5) {
        DFS(cctv, curr + 1);
    } else {
        int prev_dir = cctv[curr].dir;
        for (int dir = 0; dir <= 3; ++dir) {
            cctv[curr].dir = dir;
            DFS(cctv, curr + 1);
        }
        cctv[curr].dir = prev_dir;
    }
}

int count_hidden_area(vector<POINT>& cctv) {
    vector<vector<bool>> visited(N, vector<bool>(M, false));
    for (POINT camera : cctv) {
        set_watching_area(cctv, visited, camera);
    }

    int watching_tile_cnt = 0;
    for (int row = 0; row < N; ++row) {
        for (int col = 0; col < M; ++col) {
            if (board[row][col] == 6) continue;
            else if (visited[row][col]) {
                watching_tile_cnt += 1;
            }
        }
    }

    return (total_area - watching_tile_cnt > 0 ?
        total_area - watching_tile_cnt : 0);
}

void set_watching_area(vector<POINT>& cctv,
    vector<vector<bool>>& visited, POINT& camera) {
    for (int dir : cctv_type[camera.type]) {
        dir = (dir + camera.dir) % 4;

        for (int dist = 1; dist < max(N, M); ++dist) {
            int new_row = camera.row + dir_row[dir] * dist;
            int new_col = camera.col + dir_col[dir] * dist;

            if (new_row < 0 || new_row >= N || new_col < 0 || new_col >= M)
                continue;
            if (board[new_row][new_col] == 6)
                break;
            if (board[new_row][new_col] == 0) {
                visited[new_row][new_col] = true;
            }
        }
    }
}


실행 결과

결과

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.