Baekjoon
14502 - 연구소
kjy0349
2022. 12. 28. 17:28
1. 서론
4방향 bfs 문제이다. N, M의 범위가 8이고, 벽의 개수가 3으로 정해져 있어 어렵지 않게 풀 수 있었다.
완전탐색을해도 재귀의 깊이가 3밖에 되지 않으므로, 벽/바이러스가 하나도 없다고 생각하고 벽을 3개 세운다고 하더라도 64C3번의 연산만 하면 된다.(=41664회)
2. 풀이
문제에서 중요하게 생각해야될것은 하나이다.
벽을 세운 후, 바이러스가 퍼지는것을 구현하고 안전영역의 개수를 구해야 한다. 이 때, 바이러스가 퍼지는것은 경우의 수 때 마다 다르므로 기존맵을 복사한 후 각각 사용해야 한다.
-> 바이러스가 퍼질 때는 기존 맵에 3개의 벽을 세운 후이다. 따라서 재귀 깊이 3에 도달했을 때, 기존 맵을 복사해 새로운 맵을 만든 후 해당 맵에서 bfs를 통해 바이러스가 퍼져나가는것을 시뮬레이션하면 된다.
BFS 부분 코드
public static void bfs(int x, int depth) {
if (depth == 3) { // 재귀 깊이가 3일 때. 벽을 다 세웠으므로, 바이러스가 퍼져나가는것을 dfs를 통해 시뮬레이션한다.
int result = init_safe;
int[][] sub_map = new int[map.length][map[0].length];
for (int i = 0; i < sub_map.length; i++) sub_map[i] = map[i].clone(); // 기존 맵을 복사해 시뮬레이션용 맵을 새로 만든다.
Queue<Cord> queue = new LinkedList<>(virus);
while (!queue.isEmpty()) {
Cord elem = queue.poll();
for (int i = 0; i < 4; i++) {
int nx = dx[i] + elem.x;
int ny = dy[i] + elem.y;
if (nx >= 0 && nx < map.length && ny >= 0 && ny < map[0].length
&& sub_map[nx][ny] == 0) {
queue.add(new Cord(nx, ny));
sub_map[nx][ny] = 2;
result--;
}
}
}
if (result > answer) answer = result;
} else {
for (int i = x; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
if (map[i][j] == 0) {
map[i][j] = 1;
bfs(i, depth + 1);
map[i][j] = 0;
}
}
}
}
}
이 외에는 main에서 입력을 받고, 초깃값들을 세팅하는것 뿐이다.
전체 코드
import java.util.*;
public class P_14502 {
static ArrayList<Cord> virus;
static int[][] map;
static int[] dx = {0, 0, 1, -1};
static int[] dy = {1, -1, 0 , 0};
static int answer;
static int init_safe;
static class Cord {
int x;
int y;
Cord(int x, int y) {
this.x = x;
this.y = y;
}
}
public static void bfs(int x, int depth) {
if (depth == 3) { // 재귀 깊이가 3일 때. 벽을 다 세웠으므로, 바이러스가 퍼져나가는것을 dfs를 통해 시뮬레이션한다.
int result = init_safe;
int[][] sub_map = new int[map.length][map[0].length];
for (int i = 0; i < sub_map.length; i++) sub_map[i] = map[i].clone(); // 기존 맵을 복사해 시뮬레이션용 맵을 새로 만든다.
Queue<Cord> queue = new LinkedList<>(virus);
while (!queue.isEmpty()) {
Cord elem = queue.poll();
for (int i = 0; i < 4; i++) {
int nx = dx[i] + elem.x;
int ny = dy[i] + elem.y;
if (nx >= 0 && nx < map.length && ny >= 0 && ny < map[0].length
&& sub_map[nx][ny] == 0) {
queue.add(new Cord(nx, ny));
sub_map[nx][ny] = 2;
result--;
}
}
}
if (result > answer) answer = result;
} else {
for (int i = x; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
if (map[i][j] == 0) {
map[i][j] = 1;
bfs(i, depth + 1);
map[i][j] = 0;
}
}
}
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
int M = scan.nextInt();
scan.nextLine();
map = new int[N][M];
virus = new ArrayList<>();
init_safe = 0; // 초기 안전영역의 크기
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
map[i][j] = scan.nextInt();
if (map[i][j] == 2) virus.add(new Cord(i ,j));
else if (map[i][j] == 0) init_safe++;
}
scan.nextLine();
}
init_safe -= 3; // 벽을 세울것이기 때문에, 최대 벽 개수인 3개를 미리 빼줌(안전영역이 아님)
answer = 0;
bfs(0, 0);
System.out.println(answer);
}
}