[17141 연구소2]
난이도: 골드4
17141번: 연구소 2
인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 승원이는 연구소의 특정 위치에 바이러스 M개를 놓을 것이고, 승원이의 신호와 동시에 바이
www.acmicpc.net
문제

입력
출력
[아이디어]
바이러스가 들어갈 자리에서 M개를 조합으로 선택하여 완전 탐색하는 방법이다.
사방면으로 바이러스가 퍼져나갈 수 있고, 최소 시간을 구하는 문제이기 때문에 BFS를 사용하였다.
그 외는 단순한데, Queue에 처음 바이러스 자리 M개를 초기화 시켜줄 때 전체 맵을 탐색할지 M개를 바로 넣을지를 고민하였다. 직접 해본 시간이 별로 차이나지 않으므로 아무거나 써도 될 것 같다!
[JAVA 코드]
1. M개를 바로 초기화
// 메모리: 41388KB
// 시간: 220ms
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokens;
static int N, M, result = Integer.MAX_VALUE;
static int [][] map;
static int [] selected;
static List<Point> virus;
static Queue<Point> Q;
static int [] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
static class Point {
int r, c;
public Point(int r, int c) {
this.r = r;
this.c = c;
}
}
public static void main(String[] args) throws IOException {
tokens = new StringTokenizer(br.readLine());
N = Integer.parseInt(tokens.nextToken());
M = Integer.parseInt(tokens.nextToken());
map = new int [N][N];
virus = new ArrayList<>();
for(int r = 0; r < N; r++) {
tokens = new StringTokenizer(br.readLine());
for(int c = 0; c < N; c++) {
map[r][c] = Integer.parseInt(tokens.nextToken());
if(map[r][c] == 2) {
map[r][c] = 0;
virus.add(new Point(r, c));
}
if(map[r][c] == 1) {
map[r][c] = -1; // 벽은 -1로 표시
}
}
}
selected = new int [M];
comb(0, 0);
if(result == Integer.MAX_VALUE) System.out.println(-1);
else System.out.println(result);
}
// 바이러스가 들어갈 수 있는 자리에 M개의 바이러스를 조합으로 넣어주기
private static void comb(int start, int cnt) {
if(cnt == M) {
result = Math.min(result, countTime());
return;
}
for(int i = start; i < virus.size(); i++) {
map[virus.get(i).r][virus.get(i).c] = 2;
selected[cnt] = i; // i번째 바이러스 자리 선택
comb(i + 1, cnt + 1);
map[virus.get(i).r][virus.get(i).c] = 0;
}
}
// 최대 시간 찾아주기
private static int countTime() {
int [][] time = new int [N][N];
Q = new LinkedList<>();
// 바이러스 위치 초기화
for(int i = 0; i < M; i++) {
Q.offer(virus.get(selected[i]));
}
// BFS
while(!Q.isEmpty()) {
Point now = Q.poll();
for(int i = 0; i < 4; i++) {
int nr = now.r + dr[i];
int nc = now.c + dc[i];
// 인덱스를 벗어나거나 빈칸이 아닌 경우
if(nr < 0 || nr >= N || nc < 0 || nc >= N ) continue;
if(map[nr][nc] != 0 || time[nr][nc] != 0) continue;
Q.offer(new Point(nr, nc));
time[nr][nc] = time[now.r][now.c]+ 1;
}
}
// 최대 걸린 시간 찾기
int maxTime = 0;
for(int r = 0; r < N; r++) {
for(int c = 0; c < N; c++) {
// 벽인경우
if(map[r][c] == -1) continue;
// 바이러스가 다 퍼지지 못한 경우
if(time[r][c] == 0 && map[r][c] == 0) {
return Integer.MAX_VALUE;
}
maxTime = Math.max(maxTime, time[r][c]);
}
}
return maxTime;
}
}
2. 전체 맵 탐색
// 메모리: 41740KB
// 시간: 240ms
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokens;
static int N, M, result = Integer.MAX_VALUE;
static int [][] map;
static List<Point> virus;
static Queue<Point> Q;
static int [] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
static class Point {
int r, c;
public Point(int r, int c) {
this.r = r;
this.c = c;
}
}
public static void main(String[] args) throws IOException {
tokens = new StringTokenizer(br.readLine());
N = Integer.parseInt(tokens.nextToken());
M = Integer.parseInt(tokens.nextToken());
map = new int [N][N];
virus = new ArrayList<>();
for(int r = 0; r < N; r++) {
tokens = new StringTokenizer(br.readLine());
for(int c = 0; c < N; c++) {
map[r][c] = Integer.parseInt(tokens.nextToken());
if(map[r][c] == 2) {
map[r][c] = 0;
virus.add(new Point(r, c));
}
if(map[r][c] == 1) {
map[r][c] = -1; // 벽은 -1로 표시
}
}
}
comb(0, 0);
if(result == Integer.MAX_VALUE) System.out.println(-1);
else System.out.println(result);
}
private static void comb(int start, int cnt) {
if(cnt == M) {
result = Math.min(result, countTime());
return;
}
for(int i = start; i < virus.size(); i++) {
map[virus.get(i).r][virus.get(i).c] = 2;
comb(i + 1, cnt + 1);
map[virus.get(i).r][virus.get(i).c] = 0;
}
}
private static int countTime() {
int [][] time = new int [N][N];
Q = new LinkedList<>();
// 바이러스 위치 초기화
for(int r = 0; r < N; r++) {
for(int c = 0; c < N; c++) {
if(map[r][c] == 2) {
Q.offer(new Point(r, c));
}
}
}
while(!Q.isEmpty()) {
Point now = Q.poll();
for(int i = 0; i < 4; i++) {
int nr = now.r + dr[i];
int nc = now.c + dc[i];
// 인덱스를 벗어나거나 빈칸이 아닌 경우
if(nr < 0 || nr >= N || nc < 0 || nc >= N ) continue;
if(map[nr][nc] != 0 || time[nr][nc] != 0) continue;
Q.offer(new Point(nr, nc));
time[nr][nc] = time[now.r][now.c]+ 1;
}
}
int maxTime = 0;
for(int r = 0; r < N; r++) {
for(int c = 0; c < N; c++) {
// 벽인경우
if(map[r][c] == -1) continue;
// 바이러스가 다 퍼지지 못한 경우
if(time[r][c] == 0 && map[r][c] == 0) {
return Integer.MAX_VALUE;
}
maxTime = Math.max(maxTime, time[r][c]);
}
}
return maxTime;
}
}
'알고리즘 > BAEKJOON' 카테고리의 다른 글
[백준] 11509 풍선 맞추기 (Java) (0) | 2022.05.20 |
---|---|
[백준] 15681 트리와 쿼리 (Java) (0) | 2022.05.20 |
[백준] 21924 도시건설 (Java) (0) | 2022.05.14 |
[백준] 3584 가장 가까운 공통 조상 (Java) (0) | 2022.05.12 |
[백준] 18405 경쟁적 전염 (Java) (0) | 2022.05.05 |
댓글