⬛ 백준 14502번. 연구소 - DFS & BFS
https://www.acmicpc.net/problem/14502
문제
인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다.
연구소는 크기가 N×M인 직사각형으로 나타낼 수 있으며, 직사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽으로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다.
일부 칸은 바이러스가 존재하며, 이 바이러스는 상하좌우로 인접한 빈 칸으로 모두 퍼져나갈 수 있다. 새로 세울 수 있는 벽의 개수는 3개이며, 꼭 3개를 세워야 한다.
예를 들어, 아래와 같이 연구소가 생긴 경우를 살펴보자.
2 0 0 0 1 1 0
0 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
이때, 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 곳이다. 아무런 벽을 세우지 않는다면, 바이러스는 모든 빈 칸으로 퍼져나갈 수 있다.
2행 1열, 1행 2열, 4행 6열에 벽을 세운다면 지도의 모양은 아래와 같아지게 된다.
2 1 0 0 1 1 0
1 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 1 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
바이러스가 퍼진 뒤의 모습은 아래와 같아진다.
2 1 0 0 1 1 2
1 0 1 0 1 2 2
0 1 1 0 1 2 2
0 1 0 0 0 1 2
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
벽을 3개 세운 뒤, 바이러스가 퍼질 수 없는 곳을 안전 영역이라고 한다. 위의 지도에서 안전 영역의 크기는 27이다.
연구소의 지도가 주어졌을 때 얻을 수 있는 안전 영역 크기의 최댓값을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 8)
둘째 줄부터 N개의 줄에 지도의 모양이 주어진다. 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 위치이다. 2의 개수는 2보다 크거나 같고, 10보다 작거나 같은 자연수이다.
빈 칸의 개수는 3개 이상이다.
출력
첫째 줄에 얻을 수 있는 안전 영역의 최대 크기를 출력한다.
💚나의 풀이
1) 이중 for()문을 돌면서 기존에 빈칸값 0을 갖는 각각의 i에 대한 j에서 벽을 3개씩 세운 뒤
2) 3개 세울 때마다 BFS()를 호출한 뒤 retrun 하는 식으로 풀었다.
- 이중 map은 (1) 원본 map 과 (2) virus가 뻗어간 map 2개를 사용했다.
- 원본을 갖고 있어야 하므로 DFS 에서 뻗어갈 때, 복귀 시, 다시 기존 값으로 세팅하도록 했고
- virus는 BFS()에서 매번 새롭게 생성하여 2인 바이러스가 뻗어갈 수 있는 한 모두 뻗어가도록 하다가, 그럼에도 남아있는 0의 영역을 cnt로 ++ 처리하여 최종 정적변수인 max값을 갱신시키도록 하였다.
- 결과적으로 DFS()로 벽 3개를 매번 세우고, 3번 세운 상태의 map에서 BFS()로 바이러스가 뻗어가도록 처리한 뒤, 남아있는 0의 영역을 매번 체크하는 방식이다.
package to_1006_1;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
/*14502번. 연구소 - DFS & BFS 문풀 */
public class Main {
static int N, M;
static int[][] map;
//4방향
static int[] dx = {0, 0, 1, -1};
static int[] dy = {1, -1, 0, 0};
static int[][] virusMap;//얘는 BFS 할때마다 갱신될 용도긴 함
//max
static int max = Integer.MIN_VALUE;
//DFS -> 벽 3개씩 세우기
static void DFS(int wall) {//시작 벽 개수
if(wall == 3) {
//3개가 세워졌을 떄
BFS();///호출시킴 2 퍼뜨려야 하니까
return;//복귀
}
for(int i=0; i<N; i++) {
for(int j=0; j<M; j++) {
if(map[i][j] == 0) {//0인 지점에서
map[i][j] = 1;
DFS(wall+1);//벽 하나 세우고 깊이 탐색
//돌아오면 초기화
map[i][j] = 0;//0처리
}
}
}
}
//BFS -> 3개씩 세워질 때마다 BFS로 바이러스 퍼뜨리기
static void BFS() {
Queue<int[]> Q = new LinkedList<>();
virusMap = new int[N][M];//새롭게 2 뻗어가는 애들 만들거고
for(int i=0; i<N; i++) {
for(int j=0; j<M; j++) {
virusMap[i][j] = map[i][j];//복사시킨 뒤
if(virusMap[i][j] == 2) {
//바이러스 존재하는 애들을
Q.offer(new int[] {i, j});
}
}
}
//1) 3개 세운 상태에서 2의 시작점이 뻗어갈 수 있는 곳까지 다 뻗어간 뒤에
while(!Q.isEmpty()) {
int[] cur = Q.poll();
for(int k=0; k<4; k++) {
int nx = cur[0] + dx[k];
int ny = cur[1] + dy[k];
if(nx <0 || ny <0 || nx>=N || ny>=M )continue;
if(virusMap[nx][ny] == 0) { //닿을 수 있는 0인 지점을 모두 뻗어감
//바이러스로 뻗어갈 수 있는 곳까지 뻗어감
virusMap[nx][ny] = 2;
Q.offer(new int[] {nx, ny});
}
}
}
//2) 그럼에도 여전히 0으로 남아있는 영역을 max로 갱신시키면 됨
int cnt = 0;
for(int i=0; i<N; i++) {
for(int j=0; j<M; j++) {
if(virusMap[i][j] == 0) {
//남아있는 0의 영역에 대하여
cnt++;
}
}
}
//max값을 갱신
max = Math.max(max, cnt);//더 큰 값으로
}
//실행 메인
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
map = new int[N][M];
for(int i=0; i<N; i++) {
st = new StringTokenizer(br.readLine());
for(int j=0; j<M; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
DFS(0);
System.out.println(max);
}
}
'코딩 테스트 [준비] > [문풀] Baekjoon_백준 문풀_조지기' 카테고리의 다른 글
백준 | 22352번. 항체 인식 - BFS 풀이 (0) | 2023.10.25 |
---|---|
백준 | 4195번. 친구 네트워크 - 유니온 & 파인드, HashMap (0) | 2023.10.11 |
백준 | 13458번. 시험 감독 - 단순 구현 & 사칙연산 (0) | 2023.10.05 |
백준 | 16202번. MST 게임 - 최소 신장 트리 (0) | 2023.10.02 |
백준 | 1613번. 역사 - 플로이드 문풀 (0) | 2023.09.28 |