백준문제풀이/구현

15683번-감시

반응형

문제

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

 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감

www.acmicpc.net


접근방법

1) 접근 사고

1.CCTV의 갯수만큼 DFS를 진행해야 합니다. 각 재귀함수마다 회전할 수 있는 방향의 경우의 수를 계산해야 하기 때문입니다.

2.DFS를 진행한 뒤에는 방향을 회전시킵니다.

3.1 ~ 2를 반복한 뒤에 탐색이 CCTV의 모든 경우를 탐색했다면 안전 구역의 값을 최소값으로 최신화 합니다.

 

2) 시간 복잡도

완전 탐색이므로 O(N^2)을 가집니다.

 

3) 배운 점

방향에 대한 전환이 각 경우마다 다르기 때문에 구현할 때 실수를 했습니다. 덕분에 디버깅 실력이 늘었네요

 

4) PS

구현 문제는 기능별로 분할하는것이 디버깅할 때 훨씬 편합니다.


정답 코드

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<bits/stdc++.h>
 
#define fastio ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define pii pair<int,int>
#define mp(X, Y) make_pair(X,Y)
#define mt(X, Y) make_tuple(X,Y)
#define mtt(X, Y, Z) make_tuple(X,Y,Z)
#define ll long long
#define sz(v) (int)(v).size()
/*
4 6
0 0 0 0 0 0
0 0 6 0 0 0
0 6 3 6 0 0
0 0 6 0 0 0
 */
using namespace std;
const int MAX = 9;
int n, m;
int board[MAX][MAX];
int ret = INT_MAX;
 
vector<pair<intint>> cctv;
 
int main(void) {
    cout << (1 << 6<<"\n";
    fastio;
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> board[i][j];
            if (board[i][j] >= 1 && board[i][j] <= 5)
                cctv.push_back({i, j});
        }
    }
 
    //board의 안전구역을 탐핵한다.
    auto search = [&](int b[MAX][MAX]) -> int {
        int cnt = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                if (b[i][j] == 0)
                    cnt++;
        return cnt;
    };
 
    //y축인 경우에 0이 아니라면 음수 연산을 취한뒤 변경해주면 4방향으로 회전이 가능하다.
    auto rotate = [&](vector<pair<intint>> &dir) {
        for (int i = 0; i < dir.size(); i++) {
            if(dir[i].first != 0)
            {
                dir[i].first *= -1;
                dir[i].second *= -1;
                swap(dir[i].first, dir[i].second);
            }
            else
                swap(dir[i].first, dir[i].second);
        }
    };
 
    //방향 값을 가지고 안전구역을 체크한다.
    auto check = [&](int level, int tmpboard[MAX][MAX], vector<pair<intint>> &dir) {
        pair<intint> pos = cctv[level];
 
        for (int i = 0; i < dir.size(); i++) {
            int ny = pos.first;
            int nx = pos.second;
            while (1) {
                ny += dir[i].first;
                nx += dir[i].second;
                if (ny < 0 || ny >= n || nx < 0 || nx >= m)
                    break ;
                if(tmpboard[ny][nx] == 6)
                    break ;
                if (tmpboard[ny][nx] == 0)
                    tmpboard[ny][nx] = 23002300;
            }
        }
    };
 
    auto DFS = [&](int level, int b[MAX][MAX], auto &&DFS) -> void {
        if (cctv.size() == level) {
            ret = min(ret, search(b));
            return;
        }
        int cycle = 0;
        vector<pair<intint>> dir;
 
        if (board[cctv[level].first][cctv[level].second] == 1) { //1번 CCTV인 경우
            cycle = 4;
            dir.push_back({01});
        } else if (board[cctv[level].first][cctv[level].second] == 2) { //2번 CCTV인 경우
            cycle = 2;
            dir.push_back({01}), dir.push_back({0-1});
        } else if (board[cctv[level].first][cctv[level].second] == 3) { //3번 CCTV인 경우
            cycle = 4;
            dir.push_back({-10}), dir.push_back({01});
        } else if (board[cctv[level].first][cctv[level].second] == 4) { //4번 CCTV인 경우
            cycle = 4;
            dir.push_back({-10}), dir.push_back({01}), dir.push_back({0-1});
        } else if (board[cctv[level].first][cctv[level].second] == 5) { //5번 CCTV인 경우
            cycle = 1;
            dir.push_back({-10}), dir.push_back({01}), dir.push_back({10}), dir.push_back({0-1});
        }
 
        int tmpboard[MAX][MAX];
        for (int i = 0; i < cycle; i++) {
            memcpy(tmpboard, b, sizeof tmpboard);
            //방향 값들을 회전 시킨다.
            rotate(dir);
            //보드의 방향으로 감시영역을 체크해준다.
            check(level, tmpboard, dir);
            //다음 CCTV에서 탐색이 가능한 경우를 위해 DFS 탐색에 들어간다.
            DFS(level + 1, tmpboard, DFS);
        }
        return;
    };
 
    DFS(0, board, DFS);
 
    cout << ret << "\n";
    return 0;
}
cs
반응형

'백준문제풀이 > 구현' 카테고리의 다른 글

15685번-드래곤커브  (0) 2021.09.08
15684번-사다리조작  (0) 2021.09.07
14891번-톱니바퀴  (0) 2021.09.05
14890번-경사로  (0) 2021.09.04
14503번-로봇청소기  (0) 2021.09.04