[백준 2573] 빙산(Java)

최민길(Gale)·2023년 2월 5일
1

알고리즘

목록 보기
32/172

문제 링크 : https://www.acmicpc.net/problem/2573

이 문제는 dfs와 문제의 로직을 잘 구현하면 풀 수 있습니다.

문제의 로직은 다음과 같습니다.

  1. while(true) 반복문을 돈다.
  2. 현재의 빙산 개수를 체크한다.
  3. 만약 빙산 개수가 2 이상이라면 break 후 결과를 출력한다.
  4. 빙산이 다 녹을 때까지 분리되지 않으면 break 후 0을 출력한다.
  5. 주위의 0의 수만큼 빙산 수를 줄인다.

여기서 주의할 점은 4번과 5번입니다. 4번의 경우 이중 for문을 또 만들어 진행하기보다는 처음에 빙산을 입력받을 때 remain 변수에 빙산 수를 저장하고, 빙산이 없어질때마다 remain-- 하여 remain==0일 경우를 찾아 출력하시면 됩니다. 5번의 경우는 만약 이중 for문을 돌릴 때 그때그때 빙산을 줄인다면 늦게 녹는 빙하는 주위에 0이 더 많아져 잘못된 결과가 발생합니다. 따라서 배열에 녹을 수치를 미리 저장한 후 이후 해당값만큼 빼주면 되겠습니다.

다음은 코드입니다.

import java.util.*;
import java.io.*;

public class Main{
    static int N,M;
    static int[][] req = new int[301][301];
    static boolean[][] check;
    static int[][] meltedIceberg = new int[301][301];
    static int cnt;
    static int remain = 0;
    static int res = 0;
    static int[] dx = {1,0,-1,0};
    static int[] dy = {0,1,0,-1};

    static void meltIceberg(int y, int x){
        int num = 0;
        for(int i=0;i<4;i++){
            int ny = y + dy[i];
            int nx = x + dx[i];
            if(ny<0 || ny>=N || nx<0 || nx>=M) continue;

            // 빙산의 수만큼 num++
            if(req[ny][nx] == 0) num++;
        }

        meltedIceberg[y][x] = num;
    }

    // dfs로 빙산 개수 세기
    static void checkSameIceberg(int y, int x){
        check[y][x] = true;

        for(int i=0;i<4;i++){
            int ny = y + dy[i];
            int nx = x + dx[i];
            if(ny<0 || ny>=N || nx<0 || nx>=M) continue;

            // 0은 빙산이 아니므로 제외
            if(!check[ny][nx] && req[ny][nx] != 0){
                checkSameIceberg(ny,nx);
            }
        }
    }

    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());

        for(int i=0;i<N;i++){
            st = new StringTokenizer(br.readLine());
            for(int j=0;j<M;j++){
                req[i][j] = Integer.parseInt(st.nextToken());
                if(req[i][j]!=0) remain++;
            }
        }

        int idx = 0;
        while(true){
            // 현재 빙산의 개수 체크
            check = new boolean[301][301];
            cnt = 0;
            for(int i=0;i<N;i++){
                for(int j=0;j<M;j++){
                    if(!check[i][j] && req[i][j] != 0){
                        checkSameIceberg(i,j);
                        cnt++;
                    }
                }
            }

            // 만약 빙산의 개수가 2 이상이라면 res = cnt
            if(cnt>=2){
                res = idx;
                break;
            }

            // 빙산이 다 녹을때까지 분리되지 않으면 그대로 종료
            if(remain==0) break;

            // 주위의 0의 수만큼 빙산 수 줄이기
            // 이때 빙산이 동시에 녹지 않아 늦게 녹는 빙하는 주위에 0이 더 많아져 잘못된 결과 발생하므로 배열에 데이터 저장
            meltedIceberg = new int[301][301];
            for(int i=0;i<N;i++){
                for(int j=0;j<M;j++){
                    if(req[i][j] != 0) meltIceberg(i,j);
                }
            }

            for(int i=0;i<N;i++){
                for(int j=0;j<M;j++){
                    if(req[i][j] != 0){
                        req[i][j] -= meltedIceberg[i][j];
                        if(req[i][j]<=0){
                            req[i][j] = 0;
                            remain--;
                        }
                    }
                }
            }
            idx++;
        }
        System.out.println(res);
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보