본문 바로가기
Problem Solving/Baekjoon Online Judge

#15683 감시

by 사향낭 2022. 1. 6.

문제 링크 : https://www.acmicpc.net/problem/15683

 

15683번: 감시

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

www.acmicpc.net

 

딱 봐도 Brute-force로 풀리는 문제다. 구현하는게 번거로울 것 같다만..

 

 

일단 cctv의 유형에 따라 볼 수 감시할 수 있는 방향의 차이가 있기에 이를 먼저 어떻게 처리할지 생각해야 한다.

 

cctv가 보는 방향을 바꿀 수도 있기 때문에 방향까지 고려해줘야 한다.

 

cctv의 타입에 따라, cctv의 방향에 따라, 감시할 수 있는 방향들을 3차원 백터의 형태로 만들어 사용할 수 있을 것이다.

// (북, 동, 남, 서) = (0, 1, 2, 3)
// 각각 cctv가 북, 동, 남, 서를 볼 때 감지 가능한 방향
{ 
   { {0}, {1}, {2}, {3} }, // Type 1
   { {0, 2}, {1, 3}}, // Type 2
   { {0, 1}, {1, 2}, {2, 3}, {3, 0}}, // Type 3
   { {0, 1, 2}, {1, 2, 3}, {2, 3, 0}, {3, 0, 1}}, // Type 4
   { {0, 1, 2, 3} } // Type 5
}

 

아니면 약간의 중복이 있겠지만 방향을 돌리는 로직을 감시 가능한 영역을 확인할 때 추가한다면 2차원 백터로도 충분하다.

// (북, 동, 남, 서) = (0, 1, 2, 3)
{ 
   {0}, // Type 1
   {0, 2}, // Type 2
   {0, 1}}, // Type 3
   {0, 1, 2}, // Type 4
   {0, 1, 2, 3} // Type 5
}

// 이 다음 다른 방향들을 고려할 때
// 0부터 3까지 더해주며 (모듈러 연산 필요) 방향 전환

 

그 다음 실제로 감시 가능한 영역을 확인하여 사각 지대의 최소값을 구해야 한다.

 

recursive function 을 만드는 게 편할 것 같다는 생각이 든다.

 

감시 가능한지 여부를 썼다 지웠다 하는 건 힘든 일이기 때문에 현재 상태를 vector 형태로 그대로 넘겨 줄 것이다.

(reference 사용 x, 고대로 넘겨줘서 copy 해야함)

 

 

대충 계산했을 때, 최대 cctv의 개수 8, 최대 가로, 세로 길이 8, 고려해야 하는 cctv의 방향 경우의 수 4 이므로

 

Time Complexity $$O((8 + 8) * 4^8) = O(2^{20}) \approx O(10^7) $$

 

넉넉하다.

 

메모리도 대충 $$4^8 * 8 * 8 * 4 = 2^{24} \text{Bytes} = 16 \text{MB}$$

 

정도로 충분할 것으로 보인다.

 

 

코드는 나중에 짜야지

 

#include <bits/stdc++.h>

using namespace std;

int n, m;
vector<vector<int> > state(8, vector<int>(8));
int dir_x[] = {0, 1, 0, -1}, dir_y[] = {-1, 0, 1, 0};
vector<pair<int, int> > cctv_dir{{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
vector<vector<vector<int> > > cctv;
vector<pair<int, int> > cctv_pos;

void initiate_cctv() {
    vector<vector<int> > first;
    for (int i = 0; i < 4; i++) {
        vector<int> tmp{i};
        first.push_back(tmp);
    }
    cctv.push_back(first);

    vector<vector<int> > second;
    for (int i = 0; i < 2; i++) {
        vector<int> tmp{i, i + 2};
        second.push_back(tmp);
    }
    cctv.push_back(second);

    vector<vector<int> > third;
    for (int i = 0; i < 4; i++) {
        vector<int> tmp{i, (i + 1) % 4};
        third.push_back(tmp);
    }
    cctv.push_back(third);

    vector<vector<int> > fourth;
    for (int i = 0; i < 4; i++) {
        vector<int> tmp{i, (i + 1) % 4, (i + 2) % 4};
        fourth.push_back(tmp);
    }
    cctv.push_back(fourth);

    vector<vector<int> > fifth;
    vector<int> tmp;
    for (int i = 0; i < 4; i++) {
        tmp.push_back(i);
    }
    fifth.push_back(tmp);
    cctv.push_back(fifth);
}

bool cant_move(pair<int, int> pos) {
    int x = pos.first, y = pos.second;
    return ((x < 0) || (y < 0) || (x == m) || (y == n) || (state[x][y] == 6));
}

int perform_cctv(vector<vector<int> > &cur_state, pair<int, int> &cur_cctv,
                 int cur_dir) {
    int cur_x = cur_cctv.first, cur_y = cur_cctv.second;
    int cur_type = state[cur_x][cur_y] - 1;
    int ret = 0;

    for (auto dir : cctv[cur_type][cur_dir]) {
        int new_x = cur_x + dir_x[dir];
        int new_y = cur_y + dir_y[dir];

        while (!cant_move({new_x, new_y})) {
            if (cur_state[new_x][new_y] == 0) {
                cur_state[new_x][new_y] = -1;
                ret++;
            }
            new_x += dir_x[dir];
            new_y += dir_y[dir];
        }
    }

    return ret;
}

int perform_cctvs(vector<vector<int> > cur_state) {
    if (cctv_pos.empty()) {
        return 0;
    }

    pair<int, int> cur_cctv = cctv_pos.back();
    int cctv_x = cur_cctv.first, cctv_y = cur_cctv.second;
    int cctv_type = state[cctv_x][cctv_y] - 1;
    cctv_pos.pop_back();

    int max_check_cnt = 0, check_cnt;
    for (int cctv_dir = 0; cctv_dir < cctv[cctv_type].size(); cctv_dir++) {
        check_cnt = 0;
        vector<vector<int> > tmp_state(cur_state.begin(), cur_state.end());

        check_cnt += perform_cctv(tmp_state, cur_cctv, cctv_dir);
        check_cnt += perform_cctvs(tmp_state);
        max_check_cnt = max(max_check_cnt, check_cnt);
    }

    cctv_pos.push_back(cur_cctv);

    return max_check_cnt;
}

int main() {
    int wall_cnt = 0;
    initiate_cctv();

    scanf("%d %d", &n, &m);

    for (int y = 0; y < n; y++) {
        for (int x = 0; x < m; x++) {
            scanf("%d", &state[x][y]);

            if (1 <= state[x][y] && state[x][y] <= 5) {
                cctv_pos.push_back({x, y});
            } else if (state[x][y] == 6) {
                wall_cnt++;
            }
        }
    }

    int ret = n * m - wall_cnt - perform_cctvs(state) - cctv_pos.size();
    printf("%d", ret);

    return 0;
}

 

확실히 연습을 하지 않으니 실력이 많이 녹슬어서 생각보다 코드 짜는데 시간이 오래 걸렸다.

 

다른 사람들은 시간을 어떻게 줄였는지 참고해야겠다.

 

 

 

cctv 를 순회하는 것을 나는 pop_back(), push_back() 으로 처리해줬는데 그냥 인덱스만 있어도 충분했다...

시간을 조금 단축시켰다

나머지는 구조상의 문제인듯 하다. 이차원 백터를 계속 복사해서 그런듯.

'Problem Solving > Baekjoon Online Judge' 카테고리의 다른 글

제1회 블롭컵  (0) 2022.03.01
#2749 피보나치 수  (0) 2022.01.10
#2933 미네랄  (0) 2022.01.08
#14809 경사로  (0) 2022.01.05
#14503 로봇 청소기  (0) 2022.01.04

댓글