일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 스택
- 배열
- 구현
- 시뮬레이션
- Java
- 완전탐색
- Python
- dfs
- BufferedReader
- 알고리즘
- 빅데이터
- 문자열
- LIS
- 탐색
- SQL
- DP
- 백트래킹
- Stack
- 백준
- 브루트포스
- BFS
- 그리디
- 새벽코딩
- 다리 만들기
- 아스키코드
- 다이나믹프로그래밍
- Queue
- 프로그래머스
- oracle
- HashMap
- Today
- Total
새벽코딩
[백준] [14502] 연구소 (JAVA) (DFS, BFS) 본문
문제
인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다.
연구소는 크기가 N×M인 직사각형으로 나타낼 수 있으며, 직사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽으로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다.
일부 칸은 바이러스가 존재하며, 이 바이러스는 상하좌우로 인접한 빈 칸으로 모두 퍼져나갈 수 있다. 새로 세울 수 있는 벽의 개수는 3개이며, 꼭 3개를 세워야 한다.
예를 들어, 아래와 같이 연구소가 생긴 경우를 살펴보자.
2 0 0 0 1 1 0
0 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
이때, 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 곳이다. 아무런 벽을 세우지 않는다면, 바이러스는 모든 빈 칸으로 퍼져나갈 수 있다.
2행 1열, 1행 2열, 4행 6열에 벽을 세운다면 지도의 모양은 아래와 같아지게 된다.
2 1 0 0 1 1 0
1 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 1 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
바이러스가 퍼진 뒤의 모습은 아래와 같아진다.
2 1 0 0 1 1 2
1 0 1 0 1 2 2
0 1 1 0 1 2 2
0 1 0 0 0 1 2
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
벽을 3개 세운 뒤, 바이러스가 퍼질 수 없는 곳을 안전 영역이라고 한다. 위의 지도에서 안전 영역의 크기는 27이다.
연구소의 지도가 주어졌을 때 얻을 수 있는 안전 영역 크기의 최댓값을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 8)
둘째 줄부터 N개의 줄에 지도의 모양이 주어진다. 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 위치이다. 2의 개수는 2보다 크거나 같고, 10보다 작거나 같은 자연수이다.
빈 칸의 개수는 3개 이상이다.
출력
첫째 줄에 얻을 수 있는 안전 영역의 최대 크기를 출력한다.
예제 입력 1 복사
7 7
2 0 0 0 1 1 0
0 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
예제 출력 1 복사
27
예제 입력 2 복사
4 6
0 0 0 0 0 0
1 0 0 0 0 2
1 1 1 0 0 2
0 0 0 0 0 2
예제 출력 2 복사
9
예제 입력 3 복사
8 8
2 0 0 0 0 0 0 2
2 0 0 0 0 0 0 2
2 0 0 0 0 0 0 2
2 0 0 0 0 0 0 2
2 0 0 0 0 0 0 2
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
예제 출력 3 복사
3
※ JAVA 코드
import java.io.*;
import java.util.*;
public class Main {
// 빈칸 0, 벽 1, 바이러스 2
static final int BLANK = 0;
static final int WALL = 1;
static final int VIRUS = 2;
// 가로세로 제한
static int N, M;
// 안전영역 크기
static int safeZoneCnt;
// 최종 답
static int dap = 0;
// 사용할 맵
static int [][] map;
// 사용할 원본 맵
static int [][] oriMap;
// 바이러스 퍼뜨릴 맵
static int [][] copyMap;
// 상하좌우 이동
static final int [] dx = {-1, 1, 0, 0};
static final int [] dy = {0, 0, -1, 1};
// 좌표를 담을 노드
static class Node {
int x, y;
Node(int x, int y){
this.x = x;
this.y = y;
}
}
static void DFS(int d) {
if(d == 3) {
BFS();
return;
}
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
if(map[i][j] == BLANK) {
map[i][j] = WALL;
DFS(d+1);
map[i][j] = BLANK;
}
}
}
}
static void copyMap() {
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
copyMap[i][j] = map[i][j];
}
}
}
static void BFS() {
Queue<Node> q = new LinkedList<>();
copyMap = new int[N+1][M+1];
// copyMap
copyMap();
// VIRUS 퍼뜨리기
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
if(copyMap[i][j] == VIRUS) {
q.offer(new Node(i, j));
}
}
}
// 큐가 빌때까지 VIRUS를 퍼뜨린다
while(!q.isEmpty()) {
Node now = q.poll();
int x = now.x;
int y = now.y;
for(int i = 0; i < 4; i++) {
int nextX = x + dx[i];
int nextY = y + dy[i];
if(nextX > 0 && nextY > 0 && nextX <= N && nextY <= M) {
// 다음 노드가 빈칸이라면
if(copyMap[nextX][nextY] == BLANK) {
// 바이러스로 채운다
copyMap[nextX][nextY] = VIRUS;
q.offer(new Node(nextX, nextY));
}
}
}
}
safeZone(copyMap);
}
static void safeZone(int[][] copyMap) {
// 안전영역 개수
safeZoneCnt = 0;
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
if(copyMap[i][j] == BLANK) {
safeZoneCnt++;
}
}
}
dap = Math.max(dap, safeZoneCnt);
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
oriMap = new int [N+1][M+1];
map = new int [N+1][M+1];
for(int i = 1; i <= N; i++) {
st = new StringTokenizer(br.readLine());
for(int j = 1; j <= M; j++) {
oriMap[i][j] = map[i][j] = Integer.parseInt(st.nextToken());
}
}
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
// 원본 배열이 빈칸이라면
if(oriMap[i][j] == BLANK) {
// 벽을 세우고
map[i][j] = WALL;
// 탐색
DFS(1);
// 원래대로 복구
map[i][j] = BLANK;
}
}
}
System.out.println(dap);
}
}
※ 생각정리
먼저 생각해야할 내용 2가지
벽의 위치는 빈칸에 랜덤으로 세워질 수 있고, 벽이 세워진 이후에 막혀있지 않는 공간은 바이러스에 잠식당한다.
N X M 크기의 map에 입력값을 저장하고, oriMap에 바뀌지 않을 원본값을 저장해둔다.
oriMap의 좌표가 빈칸이라면 해당 위치에 벽을 세우고 DFS 알고리즘을 이용해서 나머지 벽을 세운다. 이때 원본 배열의 값은 바뀌면 안되기 때문에 map배열의 값을 변경한다.
벽이 3개 세워졌다면 BFS 알고리즘을 이용해 바이러스를 퍼뜨린다. map의 해당 좌표에 바이러스가 있다면 벽이 없는 상하좌우의 좌표를 바이러스(2)로 변경한다.
모든 바이러스가 퍼졌다면, 안전영역의 개수를 센다.
DFS가 모두 끝날때까지 해당 내용을 반복한다. 자세한 내용은 주석을 적어두었다.
-새벽코딩-
'알고리즘' 카테고리의 다른 글
[백준] [1926] 그림 (0) | 2022.12.22 |
---|---|
[백준] [9205] 맥주 마시면서 걸어가기 (2) | 2022.12.16 |
[백준] [9461] 파도반 수열 (JAVA) (DP) (2) | 2022.12.14 |
[백준] [5567] 결혼식 (JAVA) (0) | 2022.12.14 |
[백준] [2178] 미로탐색 (JAVA) (0) | 2022.12.13 |