본문 바로가기
Algorithm/BOJ

[BOJ]14502번: 연구소 (c++)

by HBGB 2020. 6. 13.

https://www.acmicpc.net/problem/14502

 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크�

www.acmicpc.net

 

 

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

template<typename T>
using double_v = vector<vector<T>>;

struct pos {
	int x, y;
};

int N, M;
const int NEW_WALL = 3;
enum {LAND, WALL, VIRUS};
int dr_x[] = { 0, 1, 0, -1 };
int dr_y[] = { 1, 0, -1, 0 };
vector<pos> virus;
vector<pos> land;

// bfs로 새로 퍼진 바이러스 개수 구하기
int bfs(double_v<int> test_lab)
{
	// 큐에 바이러스 벡터의 위치값들 push
	queue<pos> q;
	for (int i = 0; i < virus.size(); ++i)
	{
		q.push(virus[i]);
	}

	int virus_cnt = 0;
	while (!q.empty())
	{
		int x = q.front().x;
		int y = q.front().y;
		q.pop();
		
		// 4방향 탐색
		for (int i = 0; i < 4; ++i)
		{
			int nx = x + dr_x[i];
			int ny = y + dr_y[i];

			// 범위를 벗어나면 continue
			if (nx < 0 || nx >= N || ny < 0 || ny >= M)
			{
				continue;
			}

			// 다음 위치가 빈 칸일 때, 바이러스 카운팅 후 큐에 push
			if (test_lab[nx][ny] == LAND)
			{
				++virus_cnt;
				test_lab[nx][ny] = VIRUS;
				q.push({nx, ny});
			}
		}
	}
	return virus_cnt;
}

// dfs로 벽 3개 만들기
int dfs(double_v<int> &lab, int cnt, int strt)
{
	/*
		벽 3개가 새로 만들어지면
		해당 조건에서 새로 퍼진 바이러스 개수 리턴
	*/
	if (cnt == NEW_WALL)
	{
		return bfs(lab);
	}

	// land 벡터를 탐색하며 저장된 위치값으로 벽 만들기
	int min_virus = 987654321;
	for (int i = strt; i < land.size(); ++i)
	{
		lab[land[i].x][land[i].y] = WALL;
			
		// 다음 인덱스부터 탐색하는 dfs재귀함수 호출. 
		// 최소값 구하기
		min_virus = min(dfs(lab, cnt + 1, i + 1), min_virus);
			
		lab[land[i].x][land[i].y] = LAND;
	}
	return min_virus;
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	// 입력
	cin >> N >> M;
	double_v<int> lab(N, vector<int>(M));

	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < M; ++j)
		{
			cin >> lab[i][j];

			// 빈 칸일 때 : land벡터에 위치값 push
			if (lab[i][j] == LAND)
			{
				land.push_back({ i, j });
			}
			// 바이러스일 때 : virus벡터에 위치값 push
			else if (lab[i][j] == VIRUS)
			{
				virus.push_back({ i, j });
			}
		}
	}

	/*
		최대 안전 영역 출력
		안전영역 : 초기 빈칸 개수 - 새로 만든 벽 개수 - 퍼진 바이러스 개수

		--> 바이러스를 최소로 퍼지도록 하는 3개의 벽을 만들어야 함.
	*/
	cout << land.size() - NEW_WALL - dfs(lab, 0, 0);

	return 0;
}

 

 

 

벽을 3개 세운 뒤, 바이러스가 퍼질 수 없는 곳을 안전 영역이라고 한다.
안전 영역 크기의 최댓값을 구하는 프로그램을 작성하시오.

위 문제에서 중점적으로 구현해야할 부분은 저 둘이다. 

 

 

 

1. map이 주어지면 빈칸에 벽을 3개 세워야 한다 --> dfs

빈칸 중에서 벽으로 만들 3개를 골라야 한다.

여기서 dfs구현이 적합함을 알 수 있다. 

또한 빈칸 중에서 고를려면 빈칸 위치 배열이 필요하다. 

입력 받을 때 한번에 해결하자.

//입력 
...
cin >> lab[i][j];

// 빈 칸일 때 : land벡터에 위치값 push
if (lab[i][j] == LAND)
{
	land.push_back({ i, j });
}

...

// dfs로 벽 3개 만들기
int dfs(double_v<int> &lab, int cnt, int strt)
{
	if (cnt == NEW_WALL)
	{
		return bfs(lab);
	}

	// land 벡터를 탐색하며 저장된 위치값으로 벽 만들기
	for (int i = strt; i < land.size(); ++i)
	{
		...	
		// 다음 인덱스부터 탐색하는 dfs재귀함수 호출. 
		dfs(lab, cnt + 1, i + 1);
		...
	}
}

 

 

 

2. 안전영역의 값을 계산하려면 바이러스가 퍼진 후의 개수를 구해야 한다 --> bfs

dfs로도 가능하지만,

여러 바이러스가 닿을 수 있는 빈땅을 한번씩만 찍어서

개수를 구하는 것이므로 bfs가 적합하다.

마찬가지로 큐에 바이러스 위치값을 push하려면

입력받을 때 바이러스 벡터를 만들어야 한다.

//입력 
...
cin >> lab[i][j];

// 바이러스일 때 : virus벡터에 위치값 push
else if (lab[i][j] == VIRUS)
{
	virus.push_back({ i, j });
}

...

// bfs로 새로 퍼진 바이러스 개수 구하기
int bfs(double_v<int> test_lab)
{
	// 큐에 바이러스 벡터의 위치값들 push
	queue<pos> q;
	for (int i = 0; i < virus.size(); ++i)
	{
		q.push(virus[i]);
	}

	int virus_cnt = 0;
	while (!q.empty())
	{
	...
	}
}

 

 

'Algorithm > BOJ' 카테고리의 다른 글

[BOJ]12886번: 돌 그룹 (c++)  (0) 2020.06.14
[BOJ]9019번: DSLR (c++)  (0) 2020.06.14
[BOJ]16948번: 데스 나이트 (c++)  (0) 2020.06.13
[BOJ]16928번: 뱀과 사다리 게임 (c++)  (0) 2020.06.13
[BOJ]12100번: 2048 (Easy) (c++)  (0) 2020.06.13

댓글