알고리즘 풀이/백준

[백준 14502] 연구소 cpp

mhko411 2021. 2. 1. 21:52
728x90

문제
연구의 크기가 NxM일 때 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 곳이다. 
바이러스가 퍼지는 것을 막기위해 벽은 3개를 세울 수 있다. 3개의 벽을 세운 뒤에 바이러스가 퍼질 수 없는 곳을 안전영역이라 하는데 안전영역 크기의 최댓값을 구하라.

입력
첫째 줄에 지도의 크기인 N, M 입력 3이상 8이하
둘째 줄부터 지도의 모양을 입력하며 바이러스인 2의 개수는 2이상 10이하이다. 빈 칸의 개수는 3개 이상

출력
안전영역의 최댓값을 출력


문제에서 반드시 3개의 벽을 세워야한다고 했다. 여기서 다음 두 가지를 구현하면된다.

1. 벽을 세우는 로직

2. 벽을 세운 후에 바이러스를 퍼트리는 로직

 

먼저 벽을 세우는 로직을 어떻게 구현하면 좋을지 생각해보자.

맵에서 0은 빈 칸이고 벽을 세울 수 있는 공간이다. 따라서 0에 해당되는 모든 칸에 대하여 벽을 세우면 될 것이다. 이때 시간복잡도를 계산해보자.

 

최대 8x8의 칸(64칸)에서 바이러스는 최소 2칸, 벽은 0칸이므로 62칸이 빈 칸이 될 수 있다. 여기서 벽을 세우는 경우의 수는 62x61x60 = 226,920이 된다. 이에 더하여 벽을 세운 후에 맵을 검색하면서 바이러스를 퍼트리기 때문에 대략 13,000,000이하가 될 것이다. (틀린 계산이라면 댓글로 지적부탁드립니다.)

 

따라서 모든 빈 칸에 대하여 3개의 벽을 세워보면 될것이다. 그렇다면 어떻게 벽을 세울 것인가?라고 했을 때 문제에서 말하는 연구소 지도를 어떻게 모델링할 것인지 생각해본다. 이 문제에서는 2차원 배열을 사용하기로 하고 빈 칸은 0, 벽은 1, 바이러스는 2로 표시한다. 맵에 대한 정보를 입력받고 맵을 탐색해본다.

 

맵 탐색 중 0이 나온다면 벽을 세우고 벽을 세우는 함수인 SetWall()이 실행되도록 한다. 이 함수에서는 3개의 벽을 세우고 3개의 벽을 세웠다면 바이러스를 퍼트리는 기능을 한다. 벽을 세우고 SetWall()가 실행되고 빠져나왔을 때 다시 해당 좌표에 0을 대입하여 빈 칸으로 해준다. (백트래킹)

 

그 다음 바이러스를 퍼트리는 로직을 구현해보자.

BFS를 통해 먼저 바이러스 주변으로 점점 퍼져나가도록 한다. 벽을 세운 맵을 복사하고 바이러스의 좌표를 큐에 담는다. 이후 BFS를 진행하여 상하좌우에 빈 칸이고 맵을 벗어나지 않는다면 바이러스를 퍼트린다.

 

바이러스를 모두 퍼트린 후에 빈 칸을 카운트하여 안전영역을 구하고 최종해와 비교하여 최댓값을 갱신하도록 한다.

#include "pch.h"
#include <iostream>
#include<algorithm>
#include<queue>
using namespace std;

int map[8][8];
int answer;
int N, M;
int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };

bool Range(int y, int x) {
	return(y >= 0 && y < N) && (x >= 0 && x < M);
}


void BFS() {
	int copy_map[8][8] = { 0, };
	queue<pair<int, int>> q;

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			copy_map[i][j] = map[i][j];
			if (map[i][j] == 2)
				q.push({ i,j });
		}
	}

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

		for (int d = 0; d < 4; d++) {
			int dy = y + dir[d][0];
			int dx = x + dir[d][1];
			if (Range(dy, dx) && copy_map[dy][dx] == 0) {
				copy_map[dy][dx] = 2;
				q.push({ dy,dx });
			}
		}
	}

	int cnt = 0;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if (copy_map[i][j] == 0)
				cnt++;
		}
	}

	answer = max(answer, cnt);
	return;
}
void SetWall(int wall) {
	if (wall == 3) {
		BFS();
		return;
	}

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if (map[i][j] == 0) {
				map[i][j] = 1;
				SetWall(wall + 1);
				map[i][j] = 0;
			}
		}
	}
}

int main()
{
	cin >> N >> M;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> map[i][j];
		}
	}
	
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if (map[i][j] == 0) {
				map[i][j] = 1;
				SetWall(1);
				map[i][j] = 0;
			}
		}
	}
	cout << answer << endl;
	return 0;
}

 

느낀점

알고리즘 문제를 이해하고 가장 먼저 어떻게 접근하면 좋을지 생각해보고 풀이방법이 떠올랐다면 어떤 기능을 구현해야하는지 정리하고 문제에서 주어진 것을 어떻게 모델링할지 생각해보도록 한다.

'알고리즘 풀이 > 백준' 카테고리의 다른 글

[백준 14889] 스타트와 링크 cpp  (0) 2021.02.02
[백준 14888] 연산자 끼워넣기 cpp  (0) 2021.02.01
[백준 6603] 로또 cpp-py  (0) 2021.01.28
[백준 3986] 좋은단어 cpp-py  (0) 2021.01.27
[백준 10773] 제로 cpp-py  (0) 2021.01.27