티스토리 뷰

코딩테스트/백준

[BJ] 14502. 연구소

jhk828 2021. 3. 26. 13:10

 

www.acmicpc.net/problem/14502

 

14502번: 연구소

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

www.acmicpc.net

 

✔ 문제 조건

1. 칸에는 빈 칸 (0), 벽 (1), 바이러스 (2)가 올 수 있다.

2. 바이러스는 상하좌우 인접한 빈 칸으로 퍼져나갈 수 있다.

2-1. 바이러스는 벽으로는 퍼져나갈 수 없다.

3. 빈칸에 벽을 세워 바이러스를 막을 수 있다. 무조건 3개의 벽을 세워야 한다.

4. 바이러스가 모두 퍼졌을 때까지 남아있는 빈칸을 안전 영역이라고 한다. 안전 영역의 크기의 최대값을 구해야 한다.

 

✔ 접근 과정

1. 무조건 벽을 3개 세워야 하는데, 벽을 세울 수 있는 모든 경우의 수를 재귀로 다 따져보면 시간 초과가 날 것이라 생각했다.

2. visited 배열을 3차원으로 선언해서 벽을 세울 때 마다 다르게 방문 체크를 할까 했지만 도저히 방법을 모르겠다.

3. 문제 조건을 다시 보니 3 ≤ N, M ≤ 8이다. 즉 연구소의 크기가 크지 않아 빈 칸에 벽을 3개 세울 수 있는 모든 경우의 수를 다 따져보아도 된다. 최악의 경우에도 64 C 3 밖에 되지 않는다.

 

✔ 해결

1. DFS를 돌며 벽 3개를 세운다.

2. 벽을 3개 다 세웠을 때마다 BFS로 바이러스를 퍼뜨린다.

3. 남아있는 안전 영역의 개수를 세고 최대값을 갱신한다.

 

✔ 주의할 점

1. DFS로 벽을 하나씩 세운 후, 다음 DFS를 재귀로 호출하고 나면 세웠던 벽을 없애야 한다.

2. BFS로 바이러스를 퍼뜨릴 때 마다 원본 map 배열에 퍼뜨리지 말고, map을 복사해서 사용해야 한다.

 

 

import java.io.*;
import java.util.*;
// 210326

public class Main_BJ_14502_연구소 {
	static int N, M, max;
	static int[][] map, mapClone;
	
	static class Virus {
		int r, c;

		public Virus(int r, int c) {
			this.r = r;
			this.c = c;
		}
	}
	
	static void makeWall(int cnt) { // dfs로 벽 세우기
		if(cnt==3) {
			spreadVirus();
			return;
		}
		
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				if(map[i][j]==0) {
					map[i][j] = 1;
					makeWall(cnt+1);
					map[i][j] = 0;
				}
			}
		}
	}
	
	static int[] dr = {-1, 0, 1, 0};
	static int[] dc = {0, -1, 0, 1};
	static void spreadVirus() { // bfs로 퍼뜨리기
		mapCopy();
		
		Queue<Virus> q = new ArrayDeque<Virus>();
		boolean[][] v = new boolean[N][M];
		
		// 1. q에 바이러스 위치 넣기
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				if(mapClone[i][j]==2) {
					q.offer(new Virus(i, j));
					v[i][j] = true;
				}
			}
		} 
		
		// 2. 퍼뜨리기
		Virus cur = null; 
		int nr, nc;
		while(!q.isEmpty()) {
			cur = q.poll();
			
			for(int d=0; d<4; d++) {
				nr = cur.r + dr[d];
				nc = cur.c + dc[d];
				
				if(nr<0 || nr>=N || nc<0 || nc>=M || v[nr][nc]) continue;
				if(mapClone[nr][nc]==0) {
					mapClone[nr][nc] = 2;
					q.offer(new Virus(nr, nc));
					v[nr][nc] = true;
				}
			}
		}
		
		// 3. 남은 safeZone 세기
		int safeZone = 0;
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				if(mapClone[i][j]==0) ++safeZone;
			}
		}
		
		max = Math.max(max, safeZone);
		
	}
	
	static void mapCopy() {
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				mapClone[i][j] = map[i][j];
			}
		}
	}
	
	public static void main(String[] args) throws Exception {
//		System.setIn(new FileInputStream("res/input_BJ_14502_연구소.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		
		N = stoi(st.nextToken());
		M = stoi(st.nextToken());
		max = 0;
		map = new int[N][M];
		mapClone = 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] = stoi(st.nextToken());
			}			
		}
		
		makeWall(0);

		System.out.println(max);
		br.close();
	}
	
	static int stoi(String str) {
		return Integer.parseInt(str);
	}
}

'코딩테스트 > 백준' 카테고리의 다른 글

[BJ] 11651. 좌표 정렬하기2  (0) 2021.03.28
[BJ] 11650. 좌표 정렬하기  (0) 2021.03.28
[BJ] 1600. 말이 되고픈 원숭이  (0) 2021.03.24
[BJ] 1149. RGB 거리  (0) 2021.03.23
[BJ] 1463. 1로 만들기  (0) 2021.03.23
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함