poksul_log

# 2573. 빙산 본문

Coding Test/BOJ

# 2573. 빙산

soyw906 2023. 3. 12. 21:23
관련 알고리즘 : 구현, 그래프 탐색

 

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

 

2573번: 빙산

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

www.acmicpc.net


문제 풀이

문제의 조건을 보면,

  • 2차원 배열의 행(N, 3<=N<=300) 과 열(M, 3<=M<=300)
  • 빙산의 높이 : 각 칸의 양의 정수 숫자 표시 (0~10 사이의 정수)
  • 바다 : 0으로 표시
  • 매 년 빙산이 줄어드는 높이 = 해당 빙산을 둘러싸고 있는 바다가 있는 칸(숫자가 0인 칸)의 개수
  • 덩어리의 기준 : 동서남북 방향 중 어느 한 방향 이상으로 붙어있는 빙산이 존재하면 한 덩어리

빙산이 두 덩어리 이상으로 분리되는 최초의 시간을 구하는 것이 문제의 목적이다.

  1. 바다와 접해있는 빙산 주변 바다 칸 수만큼 높이 차감.
  2. 2차원 배열을 돌면서 빙산이 있는 칸(0이 아닌 칸) 탐색 => BFS 이용
  3. 연결되어 있는 지점들을 돌며 방문, 방문 후 체크 => ( BFS 호출 수  = 빙산의 덩어리 수 )
0 2 3
1 0 0
3 4 5

 주의할 점 : 2차원 배열을 한 칸씩 돌며 빙산을 녹이면 안 됨!

위 표에 있는 경우를 보면,

▶ 높이가 2인 빙산(빨간색 표시)를 먼저 녹이는 경우, 2면이 바다와 맞닿아 있기 때문에 1년 후 높이가 0이 된다.

 그 이후 높이가 3인 빙산(빨간색 표시)를 녹이면, 2면이 바다와 맞닿게 되기 때문에 높이가 1이 된다.

 

하지만 정확히는 1년 후

  높이가 2인 빙산은 0으로, 높이가 3인 빙산은 2가 되어야 한다.

 


c++ 코드

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

int n, m;
int map[300][300];
int temp[300][300]; // 바다로 인해 차감되는 빙산의 높이 한번에 계산 방지용 배열
bool visit[300][300];

int dx[] = { 0, 0, 1, -1 };
int dy[] = { 1, -1, 0, 0 };

void Input()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> map[i][j];
        }
    }
}

void BFS(int a, int b)
{
    queue<pair<int, int>> Q;
    Q.push(make_pair(a, b));
    visit[a][b] = true;

    while (Q.empty() == 0)
    {
        int x = Q.front().first;
        int y = Q.front().second;
        Q.pop();

        // 탐색하고자 하는 칸의 주변 조사
        for (int i = 0; i < 4; i++)
        {
            int nx = x + dx[i];
            int ny = y + dy[i];

            if (nx >= 0 && ny >= 0 && nx < n && ny < m) // 주변 칸들이 맵 범위 내에 있다면,
            {
                if (visit[nx][ny] == false && map[nx][ny] != 0)
                {
                    visit[nx][ny] = true; // 방문 check
                    Q.push(make_pair(nx, ny));
                }
            }
        }
    }
}

int Melt(int x, int y)
{
    int cnt = 0;
    for (int i = 0; i < 4; i++)
    {
        int nx = x + dx[i];
        int ny = y + dy[i];

        if (map[nx][ny] == 0) cnt++; // 주변 바다의 개수만큼 cnt ++
    }
    return cnt;
}

void Solution()
{
    int year = 0;

    while (1)
    {
        int ice = 0;
        memset(visit, false, sizeof(visit));
        memset(temp, 0, sizeof(temp));

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (map[i][j] != 0 && visit[i][j] == false) // 빙산이 있고, 아직 방문하지 않았다면
                {
                    // bfs 한번 돌 때마다 연결된 덩어리 빙산 1개씩 추가
                    ice++;
                    BFS(i, j);
                }
            }
        }

        if (ice >= 2) { cout << year << "\n"; break; }
        if (ice == 0) { cout << 0 << "\n"; break; }

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (map[i][j] != 0)
                {
                    temp[i][j] = map[i][j] - Melt(i, j); // 저장되어있는 차감높이값 한번에 빼주기
                    if (temp[i][j] < 0) temp[i][j] = 0;
                }
            }
        }

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                map[i][j] = temp[i][j];
            }
        }

        year++;
    }
}

void Solve()
{
    Input();
    Solution();
}


int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    Solve();

    return 0;
}

'Coding Test > BOJ' 카테고리의 다른 글

# 7576. 토마토  (0) 2023.04.02
# 9205. 맥주 마시면서 걸어가기  (0) 2023.03.26
# 16197. 두 동전  (0) 2023.03.05
# 2141. 우체국  (0) 2023.02.26
# 15961. 회전 초밥  (0) 2023.02.05