[문제]
14502번: 연구소
인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크
www.acmicpc.net
[풀이 내용]
* 알고리즘 분류
- 부르트포스 알고리즘
- 너비 우선 탐색
0으로 표시된 빈칸들 중에 3곳을 골라 벽을 세워야 한다.
어떻게 3곳을 골라야 가장 안전 영역을 많이 확보할 수 있는지 모르므로 경우의 수를 모두 해봐야 한다.
그 다음 각 경우마다 바이러스가 퍼질 수 없는 안전 영역의 크기를 구하고 그 중 최댓값을 출력한다.
1. 연구소 2차원 배열에서 0으로 표시된 칸들 중에 3가지를 선택하는 경우의 수를 모두 구했다.
예를 들어 0인 칸이 20개라면 20개중에 3개를 선택하는 것이므로 20C3 인 조합의 개수와 같다.
2. 경우의 수마다 모두 다음 과정을 실행한다.
2-1. 연구소 2차원 배열에서 선택된 3개의 칸을 1로 변경한다. (원래는 모두 0이었을 테니)
2-2. 연구소에서 처음부터 2(바이러스에 감염된)였던 곳들을 너비우선탐색을 통해 위, 아래, 왼쪽, 오른쪽을 탐색하며 전파 할 수 있는지 여부를 확인한다. 전파할 수 있다면 카운트를 1증가한다.
2-3. 전파할 수 있는 카운트를 구했으면 남은 0의 개수(안전 영역)을 구한다.
= 원래 0의 개수 - 전파될 수 있는 곳의 개수(0->2) - 3(3군데는 0-> 1로 변경했으므로)
[코드]
package com.algorithm.baekjoon.gold5;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class Test02 {
public static int N; // 행
public static int M; // 열
public static int[][] lab; // 연구소
public static List<int[]> infectPlaceList = new ArrayList<>(); // 처음부터 감염된 칸들
public static boolean[][] infected; // 감염이 전파된 여부
public static int zeroCount = 0; // 빈칸의 개수
public static int count = 0; // 감염이 전파된 칸의 개수
public static int max = Integer.MIN_VALUE; // 정답
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
lab = new int[N][M];
infected = new boolean[N][M];
int num = N * M;
int[] buckets = new int[3];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {
int n = Integer.parseInt(st.nextToken());
lab[i][j] = n;
if (n == 0) {
zeroCount++;
}
if (n == 2) {
int[] infectedPlace = {i, j};
infectPlaceList.add(infectedPlace);
}
}
}
getMaxOfSafeZone(num, buckets, buckets.length);
bw.write(max + "\n");
br.close();
bw.flush();
bw.close();
}
private static void getMaxOfSafeZone(int nums, int[] buckets, int k) {
if (k == 0) {
count = 0;
for (int i = 0; i < buckets.length; i++) {
int quo = buckets[i] / M; // 행
int remain = buckets[i] % M; // 렬
lab[quo][remain] = 1;
}
for (int[] infectedPlace : infectPlaceList) {
getInfectedPlace(infectedPlace[0], infectedPlace[1]);
}
max = Math.max(max, zeroCount - count - 3);
infected = new boolean[N][M];
for (int i = 0; i < buckets.length; i++) {
int quo = buckets[i] / M; // 행
int remain = buckets[i] % M; // 렬
lab[quo][remain] = 0;
}
return;
}
int lastIndex = buckets.length - k - 1;
for (int i = 0; i < nums; i++) {
int quo = i / M; // 행
int remain = i % M; // 렬
if (lab[quo][remain] == 0) {
if (buckets.length == k) {
buckets[0] = i;
getMaxOfSafeZone(nums, buckets, k - 1);
} else {
if (buckets[lastIndex] < i) {
buckets[lastIndex + 1] = i;
getMaxOfSafeZone(nums, buckets, k - 1);
}
}
}
}
}
public static void getInfectedPlace(int x, int y) {
infected[x][y] = true;
// 위
if (checkValidation(x - 1, y) && lab[x - 1][y] == 0 && !infected[x - 1][y]) {
count++;
getInfectedPlace(x - 1, y);
}
// 아래
if (checkValidation(x + 1, y) && lab[x + 1][y] == 0 && !infected[x + 1][y]) {
count++;
getInfectedPlace(x + 1, y);
}
// 왼
if (checkValidation(x, y - 1) && lab[x][y - 1] == 0 && !infected[x][y - 1]) {
count++;
getInfectedPlace(x, y - 1);
}
// 오
if (checkValidation(x, y + 1) && lab[x][y + 1] == 0 && !infected[x][y + 1]) {
count++;
getInfectedPlace(x, y + 1);
}
}
public static boolean checkValidation(int x, int y) {
if (x < 0 || x >= lab.length || y < 0 || y >= lab[x].length) {
return false;
}
return true;
}
}
'코딩 테스트 > 백준' 카테고리의 다른 글
[백준][Gold5] 12865 - 평범한 배낭 - JAVA (0) | 2021.05.16 |
---|---|
[백준][gold5] 9251번: LCS - JAVA (0) | 2021.05.09 |
[백준][Gold1]11401-이항계수3-JAVA (0) | 2021.04.27 |
[백준][Gold1] 구간 합 구하기 - JAVA (0) | 2021.04.13 |
[백준][Gold1] 책 페이지 - JAVA (0) | 2021.04.10 |