알고리즘/백준

[백준/c++] 2573번: 빙산

녕이 2022. 5. 2. 20:05
728x90

 

 

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

 

2573번: 빙산

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

www.acmicpc.net

 

 

 

빙산 높이는 일 년마다 동서남북으로 붙은 0의 개수만큼 줄어든다. 빙산이 2 덩어리 이상으로 분리되는 최소 년을 구하라.

바다 == 0, 나머지는 빙산 높이를 의미한다.

 

while문으로 일년단위로 반복해준다. 

1. 빙산 덩어리 개수 세기 ( BFS() 탐색 )

   - while문 나가는 조건 01: 빙산이 2개 이상으로 분리되면 year 출력

   - while문 나가는 조건 02: 빙산이 다 녹을 때까지 분리되지 않으면 0 출력

2. 빙하 녹이기 ( melting()함수 )

3. year++

 

덩어리 개수는 BFS 탐색으로 넓게 탐색하다가 방문한 곳이 0이 아니고 방문하지 않은 곳이 더 이상 없다면 빠져나와서 chunk++ 개수를 증가시킨다.

  - 만약 chunk가 2개 이상이라면 year를 출력하고 끝낸다.

  - 만약 chunk가 0개라면 0을 출력하고 끝낸다.

 

빙하 녹이는 법은 3중 for문으로 상하좌우가 0이라면 해당 위치의 값을 1 감소시킨다. 연쇄적으로 0의 개수를 세는 것이 아니므로 tmp라는 임시 2차원 배열을 사용해서 빙하는 녹인다.

 

 

#include <iostream>
#include <queue>
#define MAX 301
using namespace std;
int n, m, area[MAX][MAX];
int dir[4][2] = {{-1,0}, {0,1}, {1,0}, {0,-1}};
bool visited[MAX][MAX];

void BFS(int a, int b){
    queue<pair<int, int>> q;
    q.push({a, b});
    visited[a][b] = true;
    
    while(!q.empty()){
        int x = q.front().first; int y = q.front().second;
        q.pop();
        
        for(int i=0; i<4; i++){
            int dx = x + dir[i][0];
            int dy = y + dir[i][1];
            
            if(dx<0||dy<0||dx>=n||dy>=m) continue; //범위 넘어가거나 방문한 곳이면 패스
            if(area[dx][dy] == 0 || visited[dx][dy]) continue;
            visited[dx][dy] = true;
            q.push({dx,dy});
        }
    }
}

void melting(){
    int tmp[n][m];
    for(int i=0; i<n; i++) for(int j=0; j<m; j++) tmp[i][j] = area[i][j];
    
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(area[i][j] != 0){
                for(int k=0; k<4; k++){
                    int ni = i + dir[k][0];
                    int nj = j + dir[k][1];
                    if(ni<0||nj<0||ni>=n||nj>=m) continue;
                    if(area[ni][nj] == 0 && tmp[i][j] >= 1) tmp[i][j]--;
                }
            }
        }
    }
    for(int i=0; i<n; i++) for(int j=0; j<m; j++) area[i][j] = tmp[i][j];
}

int main(){
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int year = 0, chunk = 0;
    
    cin >> n >> m;
    for(int i=0; i<n; i++) for(int j=0; j<m; j++) cin >> area[i][j];
    

    while(1){
        chunk = 0; //초기화(덩어리 개수)
        for(int i=0; i<n; i++) for(int j=0; j<m; j++) visited[i][j] = false;
        
        for(int i=0; i<n; i++){ //덩어리 개수
            for(int j=0; j<m; j++){
                if(!visited[i][j] && area[i][j] != 0){
                    BFS(i, j);
                    chunk++;
                }
            }
        }
        if(chunk >= 2) { //while 반복문 나가는 조건 1 : 빙산이 2개 이상으로 분리됨
            cout << year << '\n';
            break;
        }
        if(chunk == 0){ //while 반복문 나가는 조건 2 : 빙산이 다 녹을때까지 분리되지 않으면 0
            cout << "0\n";
            break;
        }
        
        melting(); //빙하 녹이기
        year++;
    }
    return 0;
}

 

 

 

 

 

 

728x90