포스트

[백준][17142] 연구소 3

이 포스트는 백준 사이트의 연구소 3 문제 풀이입니다.

문제

문제


해결 과정

이 문제는 조합과 탐색 을 반복적으로 수행하여 해결할 수 있습니다.

문제의 설명처럼 바이러스의 개수는 1개 이상이고 10개 이하인 개수로 지형에 존재하고
그 중 승원이가 M 개를 활성화 시켰을 때, 지형 전체에 바이러스가 전파되는 최소시간을 구하고자 합니다.

따라서 여러 바이러스 위치 중 M개를 선택하면 그에 따른 바이러스의 전파를 구현하고
전파가 지형 전체에 이뤄졌는지 확인하면서 최솟값을 구하면 됩니다.

  1. 바이러스 중 M 개를 선택
  2. M개의 바이러스에서 각각 전파 진행
  3. 전파가 왼료된 지형에서 빈 공간임에도 감염되지 않은 곳이 있으면 1번, 없으면 4번으로
  4. 전파 완료된 지형에서 가장 전파가 오래 걸린 시간 저장 및 기존 값과 비교해 최솟값 저장

위 과정을 반복적으로 수행하면 문제를 해결할 수 있습니다.


코드 구현

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
124
125
126
127
128
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

int N, M, tile_count = 0;
vector<vector<int>> board;

struct POINT {
    int row, col, dist;
};

void input(vector<POINT>& virus);
int get_shortest_diffuse_time(vector<POINT>& virus);
void diffuse_virus(vector<vector<int>>& new_board, POINT start);
int count_infect_tile(vector<vector<int>> new_board);

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

    cout << get_shortest_diffuse_time(virus);

    return 0;
}

void input(vector<POINT>& virus) {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> N >> M;
    board.assign(N, vector<int>(N, 0));
    for(int row = 0; row < N; ++row) {
        for(int col = 0; col < N; ++col) {
            cin >> board[row][col];
            if(2 == board[row][col]) {
                virus.push_back({row, col, 0});
                board[row][col] = -2;
            } else if(0 == board[row][col]) {
                board[row][col] = 2e9;
                tile_count += 1;
            } else if(1 == board[row][col]) {
                board[row][col] = -1;
            }
        }
    }
}

int get_shortest_diffuse_time(vector<POINT>& virus) {
    vector<bool> select(virus.size(), false);
    for(int v = 0; v < M; ++v) {
        select[v] = true;
    }

    int MIN = 2e9;
    do {
        auto new_board = board;
        vector<int> virus_nums;
        for(int i = 0; i < M; ++i) {
            if(select[i]) {
                virus_nums.push_back(i);
                diffuse_virus(new_board, virus[i]);
            }
        }

        for(int i : virus_nums) {
            new_board[virus[i].row][virus[i].col] = 0;
        }
        
        int infect_tile = count_infect_tile(new_board);
        if(infect_tile == -1) continue;
        MIN = min(MIN, infect_tile);
    } while(prev_permutation(select.begin(), select.end()));

    return (MIN == 2e9 ? -1 : MIN);
}

void diffuse_virus(vector<vector<int>>& new_board, POINT start) {
    queue<POINT> q;
    q.push(start);

    vector<vector<bool>> visited(N, vector<bool>(N, false));
    visited[start.row][start.col] = true;

    int dir_row[4]{-1, 1, 0, 0};
    int dir_col[4]{0, 0, -1, 1};

    while(false == q.empty()) {
        auto curr = q.front();
        q.pop();

        for(int dir = 0; dir < 4; ++dir) {
            int new_row = curr.row + dir_row[dir];
            int new_col = curr.col + dir_col[dir];

            if(new_row < 0 || new_row >= N || new_col < 0 || new_col >= N)
                continue;
            if(-1 == new_board[new_row][new_col])
                continue;
            if(visited[new_row][new_col])
                continue;
            visited[new_row][new_col] = true;

            if(-2 == new_board[new_row][new_col]) {
                q.push({new_row, new_col, curr.dist + 1});
            } else {
                new_board[new_row][new_col] = min(new_board[new_row][new_col], curr.dist + 1);
                q.push({new_row, new_col, new_board[new_row][new_col]});
            }
        }
    }
}

int count_infect_tile(vector<vector<int>> new_board) {
    int MAX = 0, infect_tile = 0;
    for(auto& row : new_board) {
        for(auto& c : row) {
            if(c == 2e9) return -1;
            else if(c == -1 || c == -2) continue;
            else MAX = max(MAX, c);
            infect_tile += 1;
        }
    }
    return (infect_tile == tile_count + M ? MAX : -1);
}


실행 결과

결과

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