본문 바로가기
알고리즘/백준 - 골드

백준 2573 빙산

by 호롤롤로루야 2021. 9. 5.

백준 2573 빙산

1. 문제 링크

https://www.acmicpc.net/problem/2573

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을

www.acmicpc.net

 

2. 문제 해결에 대한 아이디어

1. 1년이 지날 때마다 바다와 맞닿은 빙산이 최대 4까지 그 크기가 줄어든다.

2. 이때, 현재의 맵에 바로 반영하는 게 아니라, 임시 맵(copyBoard)을 만들어 다음 해의 빙산의 크기를 기록한다.

3. 나누는 이유는 현재 맵에 반영할 경우, 원래보다 맞닿는 면이 많아져 빙산이 더 녹게 계산될 수 있기 때문이다.

4. 빙산이 두 개로 나뉘어졌을때 종료해야 하므로, 매 해 빙산에서 BFS를 통해 나뉜 개수를 카운트한다.

5. 이때 BFS를 수행한 횟수를 저장하여 2개 이상으로 나뉘어져있는지 혹은 다 녹았는지를 판단한다.

6. 나뉘지도 않고 다 녹지도 않았으면 빙산을 녹인다.

 

3. 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;

public class Main {
	static int N, M;
	static int[][] board;
	static int[][] copyBoard;
	static boolean[][] visit; // 매번 나뉘어졌는지 체크
	static int day = 0;
	static int iceCount = 0;
	static int[] dirY = { 0, 0, 1, -1 };
	static int[] dirX = { 1, -1, 0, 0 };
	static Queue<Pair> devideQ = new LinkedList<>(); //

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] nm = br.readLine().split(" ");

		N = Integer.parseInt(nm[0]);
		M = Integer.parseInt(nm[1]);

		board = new int[N][M];
		copyBoard = new int[N][M];
		visit = new boolean[N][M];

		for (int i = 0; i < N; i++) {
			String[] line = br.readLine().split(" ");
			for (int j = 0; j < M; j++) {
				board[i][j] = copyBoard[i][j] = Integer.parseInt(line[j]);

			}
		}

		while (true) {
			int devideCount = 0;
			for (int i = 0; i < N; i++) {
				for (int j = 0; j < M; j++) {
					if (board[i][j] != 0 && !visit[i][j]) {
						devideQ.add(new Pair(i, j));
						divideChecker();
						devideCount++;
					}
				}
			}

			// 나뉘어진 갯수가 2 이상이면 끝
			if (devideCount >= 2)
				break;
			// 나뉘어진 갯수가 없으면 빙산이 없다는 것
			else if (devideCount < 1) {
				System.out.println(0);
				return;
			}

			day++;

			for (int i = 0; i < N; i++) {
				for (int j = 0; j < M; j++) {
					if (board[i][j] != 0) {
						melt(i, j);
					}
				}
			}

			// 다음 로직을 위해 초기화
			reset();

		}

		System.out.println(day);
		br.close();
	}

	static void melt(int y, int x) {

		int waterCount = 0;

		for (int i = 0; i < 4; i++) {
			int yy = y + dirY[i];
			int xx = x + dirX[i];

			if (board[yy][xx] == 0)
				waterCount++;

		}
		int nextStatus = board[y][x] - waterCount;
		copyBoard[y][x] = nextStatus >= 0 ? nextStatus : 0;

	}

	static void divideChecker() {
		while (!devideQ.isEmpty()) {
			Pair now = devideQ.poll();
			int y = now.y;
			int x = now.x;
			visit[y][x] = true;

			for (int i = 0; i < 4; i++) {
				int yy = y + dirY[i];
				int xx = x + dirX[i];

				if (yy < 0 || xx < 0 || yy >= N || xx >= M || visit[yy][xx] || board[yy][xx] == 0)
					continue;

				visit[yy][xx] = true;
				devideQ.add(new Pair(yy, xx));
			}
		}
	}

	static void reset() {
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				board[i][j] = copyBoard[i][j]; // 녹은 빙산의 상태값을 원래 보드로 가져옴
			}
		}
		visit = new boolean[N][M]; // 디바이드 체크를 위한 방문 배열 초기화
		devideQ.clear();
	}

}

class Pair {
	int y, x;

	public Pair(int y, int x) {
		super();
		this.y = y;
		this.x = x;
	}

}
 

4. 채점 결과

 

5. 느낀 점

1. C++로 할 땐 이차원 벡터를 사용해서, 배열 간 복사를 '=' 하나로 끝냈는데 자바는 배열로 하는 게 더 편하더라.

2. 자바 이차원 배열에 대한 deep copy 방법을 찾아보니 하나씩 복사하는게 제일 속편 해서 그렇게 하기로 했다.

3. 빙산의 다음 상태를 다른 배열에 기록하고 후에 복사, 방문 배열 초기화 등이 중요했다.

 

'알고리즘 > 백준 - 골드' 카테고리의 다른 글

백준 2174 로봇 시뮬레이션  (0) 2021.09.07
백준 4179 불!  (0) 2021.09.03
백준 2589 보물섬  (0) 2021.09.02

댓글