https://www.acmicpc.net/problem/14502
1) 추가할 벽 3개 위치 선택 => Backtracking
2) 추가할 벽 3개 위치 선택 후, 입력 행렬을 [0, 0] ~ [n, m] 차례로 확인
Queue<Coord>
, LinkedList<Coord>
: BFSboolean[][]
: 방문 확인필요없는 경우의 수 존재
- [0, 0], [0, 1], [0, 2] 조합과 [0, 2], [0, 1], [0, 0] 은 동일
=> 중복없이, 순서 상관없이 선택하는 조합으로 바꾸면, 시간 절약 가능- 하지만, 조합으로 안해도 시간 복잡도 이내이므로 그냥 했음
import java.io.*;
import java.util.*;
class Coord {
private int row;
private int col;
public Coord(int row, int col) {
this.row = row;
this.col = col;
}
public int getRow() { return row; }
public int getCol() { return col; }
}
public class Main {
static int n, m; // n x m 행렬
static int[][] originMap; // 기존 입력 행렬
static int[][] virusMap; // 바이러스 퍼져나가는 맵
static int originWallCount; // 벽 3개 추가 전, 원래 벽 개수
static int maxSafeCount; // 출력 값: 안전 영역 최대 개수
static int virusCount; // 탐색한 바이러스 퍼져나가는 영역
static int minVirusCount = Integer.MAX_VALUE; // 바이러스 퍼져나가는 최소 영역
static Queue<Coord> queue = new LinkedList<>();
static boolean[][] check;
static int[] dy = { -1, 1, 0, 0 };
static int[] dx = { 0, 0, -1, 1 };
/* Backtracking 으로 추가할 벽 3개 위치 선택 후, BFS 탐색 시작 */
/* wallCount: 현재까지 선택된 벽 개수 */
static void solution(int wallCount) {
// 추가할 벽 3개 위치 선택 완료
if (wallCount == 3) {
check = new boolean[n][m]; // 초기화
virusCount = 0;
virusMap = new int[n][m]; // originMap 을 Deep Copy
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
virusMap[i][j] = originMap[i][j];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// 바이러스 칸(2)이고 아직 방문 안한 경우 => BFS 시작
if (virusMap[i][j] == 2 && !check[i][j])
bfs(i, j);
}
}
minVirusCount = Math.min(minVirusCount, virusCount);
return;
}
// 벽 3개 선택
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// 빈 칸(0)인 경우
if (originMap[i][j] == 0) {
originMap[i][j] = 1; // 벽 추가
solution(wallCount + 1);
originMap[i][j] = 0; // Backtracking (벽 취소)
}
}
}
}
/* BFS 로 map 전체의 바이러스(2)가 퍼져나가는 영역 virusCount 를 계산 */
static void bfs(int row, int col) {
check[row][col] = true;
queue.add(new Coord(row, col));
virusCount++;
while (!queue.isEmpty()) {
Coord current = queue.remove();
for (int i = 0; i < 4; i++) {
int nextRow = current.getRow() + dy[i];
int nextCol = current.getCol() + dx[i];
if (0 <= nextRow && nextRow < n &&
0 <= nextCol && nextCol < m) {
// 빈 칸(0)이 바이러스(2)로 퍼져나감
if (virusMap[nextRow][nextCol] == 0 &&
!check[nextRow][nextCol]) {
check[nextRow][nextCol] = true;
virusMap[nextRow][nextCol] = 2;
queue.add(new Coord(nextRow, nextCol));
virusCount++;
}
}
}
}
}
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());
originMap = new int[n][m];
check = new boolean[n][m];
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < m; j++) {
originMap[i][j] = Integer.parseInt(st.nextToken());
if (originMap[i][j] == 1)
originWallCount++;
}
}
// 추가할 벽 3개 위치 선택 후, 바이러스 영역 탐색
solution(0);
// 안전 영역 최대 개수 = 전체 칸 수 - (기존 벽 수 + 3) - 전체 바이러스 칸 수
maxSafeCount = (n * m) - (originWallCount + 3) - minVirusCount;
System.out.println(maxSafeCount);
}
}