알고리즘
BOJ 17142 연구소 3
minbear
2023. 8. 23. 21:30
#BOJ 17142 연구소 3
17142번: 연구소 3
인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고,
www.acmicpc.net
#풀이
저번에 풀었던 연구소 문제와 많이 비슷하다.
일단 문제가 조금 애매 하게 나와있어서 왜 틀렸는지 몰랐다.
먼저 활성화된 바이러스가 번식을 하는데 비활성화된 바이러스를 만나면 활성화를 시킨다.
이렇게 바이러스가 벽이 아닌 모든 칸에 바이러스가 있을 때 까지 걸리는 최소 시간을 구하는 문제이다.
바이러스 중에서 m개를 골라서 활성화 시켜야 하기 때문에 그냥 간단하게 백트래킹을 사용해야 한다고 생각이 들었다. 그래서 조합으로 풀면 쉽게 풀릴 것 같아 next_permutation을 사용했다.
활성화된 바이러스를 번식시켜서 bfs를 사용하여 모든 곳에 방문을 했을 때 시간을 구하면 된다.
이 때 주의해야 할 것이 비활성화된 바이러스다.
비활성화 바이러스가 벽에 붙어 있다면 굳이 방문할 필요가 없다.
하지만 벽이 아닌 중앙에 있다면 활성을 시켜서 조금 더 빠르게 모든 칸을 방문해야 한다.
그래서 나는 그냥 벽일 때만 큐에 넣지 않고 가장 큰 시간을 구하기 전에 바이러스를 모두 -1 로 대입하고 했다.
#코드
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int dx[4] = { 1,-1,0,0 };
int dy[4] = { 0,0,1,-1 };
int arr[51][51];
int n, m;
vector<pair<int, int>> b_p;
int p[251];
int min_ans = 0x7f7f7f7f;
void solved() {
do {
queue<pair<int, int>> q;
int vis[51][51] = { 0, };
for (int i = 1; i <= b_p.size(); i++) {
if (p[i] == 1) {
q.push({b_p[i-1]});
vis[b_p[i - 1].first][b_p[i - 1].second] = -1;
}
}
while (!q.empty()) { // bfs
auto cur = q.front(); q.pop();
for (int i = 0; i < 4; i++) {
int x = dx[i] + cur.first;
int y = dy[i] + cur.second;
if (x < 1 || y < 1 || x >n || y>n || arr[x][y] == 1 || vis[x][y] != 0) continue; // 비활성화된 바이러스는 활성화됨
if (vis[cur.first][cur.second] == -1) // 활성화된 바이러스일 경우
vis[x][y] = 1;
else
vis[x][y] = vis[cur.first][cur.second] + 1;
q.push({ x,y });
}
}
int max_time = 0;
bool flag = 0;
for (int i = 0; i < b_p.size(); i++) { // 모든 바이러스는 -1 최소 시간을 구하는데 사용하지 않음
vis[b_p[i].first][b_p[i].second] = -1;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (vis[i][j] == 0 && arr[i][j] != 1) { // 빈칸인데 방문을 안했을 때
flag = 1;
break;
}
if (max_time < vis[i][j]) {
max_time = vis[i][j];
}
}
if (flag) { // 모든 빈칸이 바이러스가 아닐 때
break;
}
}
if ( flag == 0 && min_ans > max_time) {
min_ans = max_time;
}
} while (next_permutation(p+1, p+1+b_p.size())); // 바이러스중에서 m개 선택 (조합)
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> arr[i][j];
if (arr[i][j] == 2)
b_p.push_back({ i,j });
}
}
for (int i = 0; i < m; i++) {
p[b_p.size() - i] = 1;
}
solved();
if (min_ans == 0x7f7f7f7f)
min_ans = -1;
cout << min_ans << '\n';
return 0;
}