Baekjoon 2573 - 빙산 (클릭 시 이동)
문제
지구 온난화로 인하여 북극의 빙산이 녹고 있다. 빙산을 그림 1과 같이 2차원 배열에 표시한다고 하자. 빙산의 각 부분별 높이 정보는 배열의 각 칸에 양의 정수로 저장된다. 빙산 이외의 바다에 해당되는 칸에는 0이 저장된다. 그림 1에서 빈칸은 모두 0으로 채워져 있다고 생각한다.
빙산의 높이는 바닷물에 많이 접해있는 부분에서 더 빨리 줄어들기 때문에, 배열에서 빙산의 각 부분에 해당되는 칸에 있는 높이는 일년마다 그 칸에 동서남북 네 방향으로 붙어있는 0이 저장된 칸의 개수만큼 줄어든다. 단, 각 칸에 저장된 높이는 0보다 더 줄어들지 않는다. 바닷물은 호수처럼 빙산에 둘러싸여 있을 수도 있다.
2차원 배열에서 동서남북 방향으로 붙어있는 칸들은 서로 연결되어 있다고 말한다.
한 덩어리의 빙산이 주어질 때, 이 빙산이 두 덩어리 이상으로 분리되는 최초의 시간(년)을 구하는 프로그램을 작성하시오. 그림 1의 빙산에 대해서는 2가 답이다. 만일 전부 다 녹을 때까지 두 덩어리 이상으로 분리되지 않으면 프로그램은 0을 출력한다.
시간 제한 | 메모리 제한 | 제출 | 정답 | 맞힌 사람 | 정답 비율 |
---|---|---|---|---|---|
1 초 | 256 MB | 38110 | 10724 | 7021 | 25.731% |
입력
첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을 나타내는 M개의 정수가 한 개의 빈 칸을 사이에 두고 주어진다. 각 칸에 들어가는 값은 0 이상 10 이하이다. 배열에서 빙산이 차지하는 칸의 개수, 즉, 1 이상의 정수가 들어가는 칸의 개수는 10,000 개 이하이다. 배열의 첫 번째 행과 열, 마지막 행과 열에는 항상 0으로 채워진다.
출력
첫 줄에 빙산이 분리되는 최초의 시간(년)을 출력한다. 만일 빙산이 다 녹을 때까지 분리되지 않으면 0을 출력한다.
풀이
- 입력이 모두 0일 경우를 고려한다.
- (1)의 경우가 아니라면 무조건 한 덩어리가 입력으로 주어지므로 모든 배열을 돌며 각 얼음을 녹일 갯수를 세어 저장한다.
- 다시 한번 더 돌며 빙산을 녹여 없앤다.
- bfs를 수행하여 빙산의 갯수를 세고 하나의 빙산이라면 (2)부터 다시 수행한다.
- 만약 bfs를 수행하지 못한다면 0을 출력한다.(모두 녹아 없어진 경우)
과정
1. 입력이 모두 0일경우 && BFS
입력으로 빙산이 없는 경우가 주어지는것과 모두 녹아 없어진 경우는 같은 로직으로 해결할 수 있다.
입력이 모두 0이면 입력받을 때 0보다 큰 입력값의 갯수를 세면 되긴 하지만
어차피 bfs를 구현해야하므로 대체했다.
int count = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] > 0 && !visited[i][j]) { // 얼음을 만나면 bfs 수행
bfs(i, j);
count++; // 수행한 횟수를 센다(빙산의 갯수)
}
}
}
if (count > 1) //빙산이 2개 이상일 경우.
break;
else if (count == 0) { // 모두 녹아 없어진 경우.
answer = 0;
break;
}
2. 빙산 녹이기
그냥 모든 배열을 돌며 녹일 양을 저장하고 모두 탐색했다면 다시 모든 배열을 돌며 녹인다.
7번라인에 map[nr][nc] 가 1보다 작을 때인 이유는 얼음의 양이 1이고 주변의 바다(0)가 3개라면 음수값이 나온다.
(0 이하는 모두 바다로 판단하게끔 로직을 구현했기 때문)
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] > 0) {
for (int step = 0; step < 4; step++) {
int nr = i + deltas[step][0];
int nc = j + deltas[step][1];
if (isIn(nr, nc) && map[nr][nc] < 1) {
melt[i][j]++;
}
}
}
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
map[i][j] -= melt[i][j];
}
}
answer++; // 빙산을 녹이는데 걸린 시간(년)
최종 소스코드
package BJ_Practice;
import java.io.*;
import java.util.*;
public class BJ_G4_2573_빙산 {
static int N, M;
static int answer = 0;
static int[][] map;
static int[][] deltas = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
static boolean[][] visited;
static StringTokenizer st;
static class Position {
int r, c;
public Position(int r, int c) {
super();
this.r = r;
this.c = c;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
map = new int[N][M];
int melt[][] = new int[N][M];
visited = new boolean[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());
}
}
while (true) {
for (int i = 0; i < N; i++) {
Arrays.fill(visited[i], false);
Arrays.fill(melt[i], 0);
}
int count = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] > 0 && !visited[i][j]) {
bfs(i, j);
count++;
}
}
}
if (count > 1)
break;
else if (count == 0) {
answer = 0;
break;
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (map[i][j] > 0) {
for (int step = 0; step < 4; step++) {
int nr = i + deltas[step][0];
int nc = j + deltas[step][1];
if (isIn(nr, nc) && map[nr][nc] < 1) {
melt[i][j]++;
}
}
}
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
map[i][j] -= melt[i][j];
}
}
answer++;
}
System.out.println(answer);
}
static void bfs(int r, int c) {
Queue<Position> queue = new LinkedList<>();
queue.offer(new Position(r, c));
visited[r][c] = true;
while (!queue.isEmpty()) {
Position temp = queue.poll();
for (int i = 0; i < 4; i++) {
int nr = temp.r + deltas[i][0];
int nc = temp.c + deltas[i][1];
if (isIn(nr, nc) && !visited[nr][nc] && map[nr][nc] > 0) {
queue.offer(new Position(nr, nc));
visited[nr][nc] = true;
}
}
}
}
static boolean isIn(int r, int c) {
return r >= 0 && r < N && c >= 0 && c < M;
}
}
'Algorithm > BaekJoon' 카테고리의 다른 글
[백준] 1967번 - 트리의 지름 (java) (0) | 2022.01.05 |
---|---|
[백준] 15684 - 사다리 조작 (java) (0) | 2022.01.05 |
[백준] 11437번 - LCA (java) (0) | 2021.12.26 |
[백준] 3584 - 가장 가까운 공통 조상 (java) (0) | 2021.12.25 |
[백준] 11559 - Puyo Puyo (java) (0) | 2021.12.25 |