17142번: 연구소 3
인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고
www.acmicpc.net
백트래킹과 BFS를 활용하여 풀 수 있는 문제였다.
입력으로 주어지는 바이러스들과 그 바이러스를 M개 활성화 시키는 모든 경우의 수를 백트레킹을 통해 완전탐색 하고, 모든 경우에 대해 바이러스를 확산시키는 BFS를 수행하여 가장 빠르게 확산되는 시간을 구해주면 원하는 결과를 얻을 수 있다.
시간이 0.25초로 제한되어 있기 때문에 2차원배열 전체를 순회하며 활성화 된 바이러스가 있는 위치를 찾아 확산시키는 방식으로 BFS를 구현하게 된다면 최악의 경우 (50^2) * (10개중 5개를 뽑는 조합의 수 252) * 50 = 31,500,000번 연산을 수행해야 하므로 제한 시간을 초과하게 된다. 따라서 배열 전체를 순회하는 방식이 아닌, 활성화 된 바이러스의 위치를 따로 저장하여 바이러스가 존재하는 좌표에 바로 접근할 수 있도록 구현하였다.
#include <iostream>
#include <cstring>
#include <queue>
#include <list>
using namespace std;
struct Pos {
int y;
int x;
};
const int INF = 987654321;
int N, M, cnt = 0, blank = 0;
int leastTime = INF;
int board[50][50];
Pos virus[10];
int dy[4] = { 0, 0, 1, -1 };
int dx[4] = { 1, -1, 0, 0 };
int bfs(list<Pos> actVirus) {
bool visited[50][50] = { false };
for (auto x : actVirus)
visited[x.y][x.x] = true;
int change = 0;
queue <int> q;
q.push(0);
while (!q.empty()) {
int time = q.front();
q.pop();
if (change == blank) return time;
// bool isChange = false;
int listSize = actVirus.size();
for (int i = 0; i < listSize; i++) {
Pos here = actVirus.front();
actVirus.pop_front();
for (int j = 0; j < 4; j++) {
int nearY = here.y + dy[j];
int nearX = here.x + dx[j];
if (nearY >= 0 && nearY < N && nearX >= 0 && nearX < N && !visited[nearY][nearX])
if (board[nearY][nearX] == 2 || board[nearY][nearX] == 0) {
visited[nearY][nearX] = true;
// isChange = true;
actVirus.push_back({ nearY, nearX });
if (board[nearY][nearX] == 0)
change++;
}
}
}
// if (isChange) q.push(time + 1);
if (!actVirus.empty()) q.push(time + 1);
}
return INF;
}
void backtracking(int start, list<Pos>& actVirus) {
int select = actVirus.size();
if (select == M) {
leastTime = min(leastTime, bfs(actVirus));
return;
}
for (int i = start; i < cnt; i++) {
Pos pos = virus[i];
actVirus.push_back({ pos.y, pos.x });
backtracking(i + 1, actVirus);
actVirus.pop_back();
}
}
int main(void) {
cin >> N >> M;
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++) {
cin >> board[i][j];
if (board[i][j] == 2) {
virus[cnt].y = i;
virus[cnt].x = j;
cnt++;
}
else if (board[i][j] == 0)
blank++;
}
list<Pos> actVirus;
backtracking(0, actVirus);
if (leastTime == INF)
cout << -1 << endl;
else
cout << leastTime << endl;
return 0;
}

'알고리즘 > BOJ' 카테고리의 다른 글
백준 7425번: Flip Game (0) | 2021.04.22 |
---|---|
백준 1766번: 문제집 (0) | 2021.04.22 |
백준 16235번: 나무 재테크 (0) | 2021.01.16 |
백준 14890번: 경사로 (0) | 2021.01.07 |
백준 2636번: 치즈 (0) | 2021.01.04 |