조합
을 구현했습니다.BFS
를 구현했습니다.Main(){
M개의 바이러스를 실행하는 모든 조합 comb를 실행합니다.
최종 시간을 계산합니다.
}
comb(){
if(M개의 조합이 완성되면){
q에 M개의 pos조합을 넣습니다.
입력값으로 만든 2차원 배열 Board를 복사한 CopyBoard를 만듭니다.
CopyBoard와 q로 BFS를 수행합니다.
}
}
BFS(q,board){
while(q에 값이 존재하지 않을 때까지){
while(현재의 q가 0이 될 때 까지){ // 같은 depth의 좌표들이 동시에 실행됩니다.
q의 값을 하나씩 꺼내어 4방탐색을 진행합니다.
4방의 좌표 중 벽이 아니면서 아직 방문하지 않은 곳이면
해당 좌표를 방문합니다.
}
현재 depth에서 모든 공간이 바이러스로 채워졌는지(0이 존재하지 않는지) 확인합니다.
}
방문할 수 있는 모든 곳을 방문했는데도 0이 존재한다면 해당 조합으로는 모든 공간을 채우지 못하는 상황입니다.
}
ExistZero(board){
0이 존재하면 true를, 그렇지 않으면 false를 반환합니다.
}
import java.util.*;
public class Main {
static int N, M;
static int[] ans;
static List<pos> lst;
static int[] dx = { 0, 1, 0, -1 };
static int[] dy = { 1, 0, -1, 0 };
static int MinVal = Integer.MAX_VALUE;
static int[][] board;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
ans = new int[M];
board = new int[N][N];
lst = new ArrayList<pos>();
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int val = sc.nextInt();
if (val == 2) {
lst.add(new pos(i, j));
board[i][j] = 99; // 바이러스 위치
} else if (val == 1) {
board[i][j] = 999; // 벽 위치
} else {
board[i][j] = val;
}
}
}
comb(0, 0, board);
if (MinVal == 9998) {
System.out.println(-1);
} else if (!ExistZero(board)) {
System.out.println(0);
} else {
System.out.println(MinVal);
}
}
public static void comb(int depth, int start, int[][] board) {
if (depth == M) {
Queue<pos> q = new LinkedList<pos>();
for (int i = 0; i < M; i++) {
q.add(lst.get(ans[i]));
}
int[][] CopyBoard = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
CopyBoard[i][j] = new Integer(board[i][j]);
}
}
// CopyBoard에 Visited배열까지 사용해서 메모리 초과가 발생했었습니다.
MinVal = Math.min(MinVal, BFS(q, CopyBoard));
return;
}
for (int i = start; i < lst.size(); i++) {
ans[depth] = i;
comb(depth + 1, i + 1, board);
}
}
public static int BFS(Queue<pos> q, int[][] board) {
int cnt = 0;
while (!q.isEmpty()) {
int size = q.size();
cnt++;
while (--size >= 0) {
pos val = q.poll();
for (int d = 0; d < 4; d++) {
int nx = val.x + dx[d];
int ny = val.y + dy[d];
// 아직 방문하지 않은 길과 비활성 바이러스가 있는 곳을 지나갈 수 있습니다.
if (0 <= nx && nx < N && 0 <= ny && ny < N && (board[nx][ny] == 0 || board[nx][ny] == 99)) {
q.add(new pos(nx, ny));
board[nx][ny] = cnt;
}
}
if (!ExistZero(board)) {
return cnt;
}
}
}
// 모든 칸에 바이러스를 퍼뜨릴 수 없는 경우를 체크하기 위한 구간입니다.
// 곧바로 -1을 return하면 다른 경우의 수를 고려할 수 없습니다.
// ex) A,B,C를 선택했을 때 모든 칸에 바이러스를 퍼뜨리지 못했습니다. -> 만약 -1을 return하면
// 이후 B,C,D를 선택해서 5초만에 바이러스를 퍼뜨렸어도 -> Math.min(5,-1)이 되어 5초에 바이러스를 퍼뜨렸다는 결과를 얻지
// 못합니다.
if (ExistZero(board)) {
return 9998;
}
return 9999; // 실행되지 않는 코드입니다.
}
public static boolean ExistZero(int[][] board) { // 배열에 0이 존재하는지 확인합니다.
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (board[i][j] == 0)
return true;
}
}
return false;
}
static class pos {
int x;
int y;
public pos(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "pos [x=" + x + ", y=" + y + "]";
}
}
}