| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 31 |
- JOIN
- Pirogramming
- 알고리즘
- Database
- SQL코딩테스트
- 구현
- 누적합
- 다익스트라
- 백준
- 코딩테스트
- Baekjoon
- db
- SQL
- MST
- 프림
- union find
- 배포
- 프로그래머스
- django
- 그래프 탐색
- BFS
- 피로그래밍
- AWS
- OrderBy
- Java
- EC2
- 최단경로
- 자바
- GROUPBY
- 크루스칼
- Today
- Total
NullNull
[백준 P14052] 연구소 Java 본문
P14502 연구소
14502번: 연구소
인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크
www.acmicpc.net
문제
인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다.
연구소는 크기가 N×M인 직사각형으로 나타낼 수 있으며, 직사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽으로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다.
일부 칸은 바이러스가 존재하며, 이 바이러스는 상하좌우로 인접한 빈 칸으로 모두 퍼져나갈 수 있다. 새로 세울 수 있는 벽의 개수는 3개이며, 꼭 3개를 세워야 한다.
예를 들어, 아래와 같이 연구소가 생긴 경우를 살펴보자.

이때, 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 곳이다. 아무런 벽을 세우지 않는다면, 바이러스는 모든 빈 칸으로 퍼져나갈 수 있다.
2행 1열, 1행 2열, 4행 6열에 벽을 세운다면 지도의 모양은 아래와 같아지게 된다.

바이러스가 퍼진 뒤의 모습은 아래와 같아진다.

벽을 3개 세운 뒤, 바이러스가 퍼질 수 없는 곳을 안전 영역이라고 한다. 위의 지도에서 안전 영역의 크기는 27이다.
연구소의 지도가 주어졌을 때 얻을 수 있는 안전 영역 크기의 최댓값을 구하는 프로그램을 작성하시오.
입력값
첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 8)
둘째 줄부터 N개의 줄에 지도의 모양이 주어진다. 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 위치이다. 2의 개수는 2보다 크거나 같고, 10보다 작거나 같은 자연수이다.
빈 칸의 개수는 3개 이상이다.
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
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
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
출력값
첫째 줄에 얻을 수 있는 안전 영역의 최대 크기를 출력한다.
27
9
3
알고리즘
조합을 사용하면 쉽게 풀 수 있는 문제이다. 바이러스가 없는 곳에 벽을 3 개 세울 수 있다.
N의 최댓값은 8이고 바이러스는 최소 2개 있을 수 있으므로, 벽이 하나도 없는 상황이라면 8 * 8 - 2 개의 공간에 벽을 세울 수 있다. 즉 62개의 벽 중 3개를 순서와 관계없이 골라서 벽을 세웠다고 가정하고, 바이러스가 있는 좌표에서 번식할 수 있을 때 까지 탐색하면 안전 영역을 구할 수 있다. 모든 경우를 탐색하고 안전 영역이 가장 클 때의 값을 출력한다.
우선 빈 공간과 바이러스의 좌표를 저장해둔다. 그 이후에 빈 공간 중 3개를 순서 상관 없고 중복 없이 고른 이후, bfs 탐색을 한다.
public static void combination(int start, int cnt){
if (cnt == 3) {
bfs();
return;
}
for (int i = start, size = pointList.size(); i < size; i++) {
result[cnt] = i;
combination(i + 1, cnt + 1);
}
}
모든 바이러스를 시작점으로 보고 bfs 탐색을 진행한다. 만약 탐색할 다음 좌표가 범위를 벗어나거나, 원래부터 벽 이거나, 새롭게 벽으로 세운 공간인 경우에는 탐색하지 않는다. 그 이외의 경우만 큐에 좌표를 추가하여 탐색한다. 그렇게 탐색 후에 남아있는 빈 공간의 수를 저장하고 그 값이 가장 큰 경우를 정답으로 출력한다.
전체 코드는 다음과 같다.
코드
import java.util.*;
import java.io.*;
public class Main {
static final int[] dx = {1, 0, -1, 0};
static final int[] dy = {0, 1, 0, -1};
static int N, M;
static int E;
static int[][] map;
static int maxValue;
// Virus point
static List<Point> virusList = new ArrayList<>();
// Emtpy point
static List<Point> pointList = new ArrayList<>();
static int[] result = new int[3];
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
map = new int[N][M];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
if (map[i][j] == 2) {
virusList.add(new Point(i, j));
} else if (map[i][j] == 0) {
pointList.add(new Point(i, j));
}
}
}
E = pointList.size();
combination(0, 0);
System.out.println(maxValue);
}
public static void combination(int start, int cnt){
if (cnt == 3) {
bfs();
return;
}
for (int i = start, size = pointList.size(); i < size; i++) {
result[cnt] = i;
combination(i + 1, cnt + 1);
}
}
public static void bfs() {
int[][] newMap = new int[N][M];
for (int i = 0; i < 3; i++) {
int x = pointList.get(result[i]).x;
int y = pointList.get(result[i]).y;
newMap[x][y] = 1;
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] == 1) {
newMap[i][j] = 1;
}
}
}
Queue<Point> q = new LinkedList<>();
for (Point virus : virusList) {
q.add(virus);
newMap[virus.x][virus.y] = 1;
}
while (!q.isEmpty()) {
Point current = q.poll();
for (int i = 0; i < 4; i++) {
int newX = current.x + dx[i];
int newY = current.y + dy[i];
if (0 <= newX && newX < N && 0 <= newY && newY < M) {
if (map[newX][newY] == 0 && newMap[newX][newY] == 0) {
newMap[newX][newY] = 1;
q.add(new Point(newX, newY));
}
}
}
}
int total = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
total += newMap[i][j];
}
}
maxValue = Math.max(maxValue, N * M - total);
}
}
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return this.x + " " + this.y;
}
}
'알고리즘' 카테고리의 다른 글
| [백준 P1865] 웜홀 Java (1) | 2022.10.29 |
|---|---|
| [백준 P16234] 인구 이동 Java (1) | 2022.10.03 |
| [백준 P1644] 소수의 연속합 Java (0) | 2022.10.03 |
| [백준 P2887] 행성 터널 Java (2) | 2022.10.03 |
| [백준 P1854] K번째 최단경로 찾기 Java (0) | 2022.10.03 |