Problem Solving/BOJ

[BOJ] #17142 _ 연구소3

Grini 2019. 10. 22. 20:08

[연구소3] https://www.acmicpc.net/problem/17142

 

17142번: 연구소 3

인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고, 활성 상태인 바이러스는 상하좌우로 인접한 모든 빈 칸으로 동시에 복제되며, 1초가 걸린다. 승원이는 연구소의 바이러스 M개를 활성 상태로 변경하려고 한다. 연구소는 크기가 N×N인 정사각형으로 나타낼 수 있으며, 정사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는

www.acmicpc.net

조합을 이용한 문제로, 3개의 바이러스를 선택하여 가장 빠르게 퍼트리는 방법을 구현하는 문제이다.

dfs를 이용하여 조합을 구할 수 있지만, next_permutation을 이용하여 간단히 구현하였다.

코드의 동작 순서는 다음과 같다.

 

1. 처음 연구소의 상태를 lab배열에 저장하고, 선택된 바이러스를 -1로 변경한다.

2. bfs를 이용하여 퍼지는데 걸리는 최대 시간을 체크한다.

3. checkInfection() 함수를 이용하여 모든 지점에 바이러스가 퍼졌는지 확인한다.
-> 바이러스를 퍼트린후 남아있는 0의 개수를 카운트하여,
바이러스의 수보다 많으면 바이러스가 퍼지지 않은 것으로 판단하였다.

4. 모든 조합을 다 돌리면서 바이러스를 퍼트릴 수 있는 최단 시간을 구한다.
(이 때, 주의 할 점은 비활성 바이러스가 있던 구간은 시간을 체크할 때 포함하지 않아야 한다.)

 

[ 소스 코드 ]

#include <cstdio>
#include <queue>
#include <algorithm>
#define MAX 51
#define INF 999999999

using namespace std;

int dx[] = { 0,0,-1,1 }, dy[] = { -1,1,0,0 };
int n, m, min_time = INF;
int lab[MAX][MAX], tmp[MAX][MAX];
vector<pair<int, int> > virus;
vector<int> v;

void solve();
int infectVirus();
int checkInfection();
void copyLab();
int main() {
	scanf("%d %d", &n, &m);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			scanf("%d", &lab[i][j]);
			if (lab[i][j] == 2) virus.push_back(make_pair(i, j));
		}
	}

	solve();
	if (min_time == INF) printf("-1\n");
	else printf("%d\n", min_time);

	return 0;
}

void solve() {
	int tmp_min;
	for (int i = 0; i < virus.size(); i++) {
		if (i < m) v.push_back(0);
		else v.push_back(1);
	}

	do {
		copyLab();
		tmp_min = infectVirus();
		if (checkInfection()) min_time = min(min_time, tmp_min);
	} while (next_permutation(v.begin(), v.end()));
}

int infectVirus() {
	int tmp_y, tmp_x, y, x, val = 0;
	queue<pair<int, int> > q, re_q;

	for (int i = 0; i < v.size(); i++) {
		if (!v[i]) {
			lab[virus[i].first][virus[i].second] = -1;
			q.push(virus[i]);
			re_q.push(virus[i]);
		}
		tmp[virus[i].first][virus[i].second] = 0;
	}

	while (!q.empty()) {
		y = q.front().first;
		x = q.front().second;
		q.pop();

		for (int i = 0; i < 4; i++) {
			tmp_y = y + dy[i];
			tmp_x = x + dx[i];
			if (tmp_x < 0 || tmp_y < 0 || tmp_x >= n || tmp_y >= n) continue;
			if (lab[tmp_y][tmp_x] == 1) continue;
			if (lab[tmp_y][tmp_x] == -1) continue;
			if (tmp[tmp_y][tmp_x] != 0) continue;
			tmp[tmp_y][tmp_x] = tmp[y][x] + 1;
			q.push(make_pair(tmp_y, tmp_x));
			if (lab[tmp_y][tmp_x] != 2) val = max(val, tmp[tmp_y][tmp_x]);
			
		}
	}

	while (!re_q.empty()) {
		lab[re_q.front().first][re_q.front().second] = 2;
		re_q.pop();
	}

	return val;
}

int checkInfection() {
	int cnt = 0;

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (tmp[i][j] == 0 || lab[i][j] == 2) cnt++;
		}
	}
	if (cnt > virus.size()) return 0;
	return 1;
}

void copyLab() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			tmp[i][j] = lab[i][j];
		}
	}
}