acmicpc

[BAEKJOON] 17142. 연구소 3

코드와이 2021. 8. 28. 21:16

 

문제링크

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

 

17142번: 연구소 3

인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고

www.acmicpc.net

 

package acmicpc.Gold4;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;

public class 연구소3 {

	static int n, m, map[][], ans;
	static int dr[] = {-1,1,0,0};
	static int dc[] = {0,0,-1,1};
	static List<Virus> list;
	static int[] index;
	static class Virus {
		int r, c;

		public Virus(int r, int c) {
			super();
			this.r = r;
			this.c = c;
		}
		
	}
	public static void main(String[] args) throws IOException {
		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][n];
		list = new ArrayList<>();		// 바이러스들을 저장할 리스트
		
		for(int i = 0 ; i < n ; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j = 0 ; j < n ; j++) {
				map[i][j] = Integer.parseInt(st.nextToken());
				
				if(map[i][j] == 2) list.add(new Virus(i,j));
			}
		}
		index = new int[m];				// 활성화된 바이러스를 저장할 배열
		ans = 987654321;
		
		active(0, 0);
		System.out.println(ans == 987654321 ? -1 : ans);
	}
	
	// 활성화할 바이러스 고르기
	public static void active(int idx, int cnt) {
		
		if(cnt == m) {
			int time = spread();
			if(time >= 0) ans = Math.min(ans, time);
			return;
		}
		
		for(int i = idx ; i < list.size() ; i++) {
			index[cnt] = i;
			active(i + 1, cnt + 1);
		}
	}
	
	// 바이러스를 퍼뜨릴 함수
	public static int spread() {
		
		int[][] tmp = new int[n][n];
		for(int i = 0 ; i < n ; i++) {
			for(int j = 0 ; j < n ; j++) {
				tmp[i][j] = map[i][j];
			}
		}

		Queue<Virus> queue = new LinkedList<>();
		
		// 초기에 활성화된 바이러스들을 큐에 넣어준다. 
		for(int i = 0 ; i < m ; i++) {
			Virus v = list.get(index[i]);
			queue.add(new Virus(v.r, v.c));
			tmp[v.r][v.c] = 3; 
		}
		
		int time = 0;
		int virus = queue.size();

		while(true) {

			time++;
			// time 이 현재 ans 보다 같거나 크다면 break
			if(time >= ans) break;
			
			for(int i = 0 ; i < virus ; i++) {
				
				Virus v = queue.poll();
				
				for(int d = 0 ; d < 4 ; d++) {
					int nr = v.r + dr[d];
					int nc = v.c + dc[d];
					
					// 벽과 이미 바이러스가 퍼진 구역은 continue
					if(nr < 0 || nr >= n || nc < 0 || nc >= n || tmp[nr][nc] == 1 || tmp[nr][nc] == 3) continue;
					tmp[nr][nc] = 3;
					queue.add(new Virus(nr, nc));
				}
			}
			
			// 0이 없다면 break
			if(check(tmp)) break;
			
			// 0이 있는데 퍼질 구역이 없다면 모든 구역에 바이러스를 퍼뜨릴 수 없다.
			if(queue.isEmpty()) {
				time = -1;
				break;
			}
			
			// virus 갯수 최신화
			virus = queue.size();
			
		}
		
		return time;
	}
	
	// 0이 있다면 return false 
	public static boolean check(int[][] tmp) {
		for(int i = 0 ; i < n ; i++) {
			for(int j = 0 ; j < n ; j++) {
				if(tmp[i][j] == 0) return false;
			}
		}
		return true;
	}
}