import java.io.*;
import java.util.*;
class Main {
public static int N;
public static int M;
public static int[] dx = {0, 0, -1, 1};
public static int[] dy = {1, -1, 0, 0};
public static int[][] map;
public static int result = Integer.MIN_VALUE;
public static void main(String args[]) throws Exception {
// 바이러스를 막을 수 있는 경우 => 세로, 가로, 대각선
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 세로크기 N, 가로크기 M
String[] temp = br.readLine().split(" ");
N = Integer.parseInt(temp[0]);
M = Integer.parseInt(temp[1]);
// 지도, 벽을 위한 지도
map = new int[N][M];
// 지도 데이터 입력
for (int i = 0; i < N; i++) {
temp = br.readLine().split(" ");
for (int j = 0; j < temp.length; j++) {
map[i][j] = Integer.parseInt(temp[j]);
}
}
// 벽을 세우고 바이러스 퍼지게하기
makeWall(0);
// 결과 출력
System.out.println(result);
}
// 벽 세우기
public static void makeWall(int depth) {
// 벽은 세개까지 세울 수 있기 때문에
if (depth == 3) {
BFS();
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(depth + 1);
map[i][j] = 0;
}
}
}
}
public static void BFS() {
int[][] virus_map = new int[N][M];
// virus타입을 갖는 큐 선언
Queue < Virus > queue = new LinkedList < > ();
// virus_map에 벽을 세운 map을 복사
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
virus_map[i][j] = map[i][j];
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
// 해당 자리가 바이러스일 경우 큐에 넣는다.
if (virus_map[i][j] == 2) {
queue.add(new Virus(i, j));
}
}
}
while (!queue.isEmpty()) {
Virus virus = queue.poll();
// 이동할 수 있는 방향은 총 4가지(상, 하, 좌, 우)
for (int i = 0; i < 4; i++) {
int nx = virus.x + dx[i];
int ny = virus.y + dy[i];
// 범위안에 있고, 해당 자리가 빈칸일 경우 바이러스로 변경
if (isRange(nx, ny)) {
if (virus_map[nx][ny] == 0) {
virus_map[nx][ny] = 2;
queue.add(new Virus(nx, ny));
}
}
}
}
int count = 0;
// 안전지역 계산을 위한 반복문
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (virus_map[i][j] == 0) {
count++;
}
}
}
// 둘 중 더 큰 값을 result에 저장한다.
result = Math.max(count, result);
}
public static boolean isRange(int x, int y) {
if (x >= 0 && y >= 0 && x < N && y < M) {
return true;
}
return false;
}
}
class Virus {
// x축, y축
int x, y;
public Virus(int x, int y) {
this.x = x;
this.y = y;
}
}
해결방법
이전에 연산자 끼워넣기와 데스 나이트를 풀었다면 해결할 수 있는 문제였다.
makeWall()
의 경우, DFS를 기반으로 코드를 구성하였다. 문제에서 벽은 총 3개까지만 세울 수 있으므로 depth가 3이될 때 BFS()
를 호출한다.
모든 경우의 수를 구해야하므로 이중 반복문을 통해 해당 인덱스가 0일 경우 벽을 세우고 makeWall()
을 다시 호출하였다. 그 후, 다음 반복문을 위해 해당 인덱스를 다시 초기화해주었다.
BFS()
의 경우, 이전에 풀었던 데스 나이트 문제를 기반으로 코드를 구성하였다.
virus_map변수는 BFS()
가 호출된 시점의 맵 상태를 가져와야하기 때문에 반복문을 통해 맵의 정보를 복사해주었다. 이때, virus_map = map과 같은 방법은 얕은 복사이기 때문에 정보가 복사되지 않는다는 것을 알았다.
그 이후의 과정은 벽으로 막혀있는 부분을 제외한 나머지 부분을 바이러스가 감염시키는 과정으로 큐에 가장 앞에 있는 바이러스를 뽑은 후 해당 바이러스의 상, 하, 좌, 우로 빈칸일 경우 감염시켜주었다.
모든 과정이 끝난 후, 반복문을 돌리며 인덱스가 0인 부분에 대해 count값을 1증가시켜주었고, 안전지대가 제일 많은 것을 저장해야하기 때문에 비교를 통하여 result변수에 저장해주었다.