ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [BOJ / C++] 1245번 : 농장 관리
    Study (etc)/Problem Solving 2023. 8. 16. 17:31

    문제

    농부 민식이가 관리하는 농장은 N×M 격자로 이루어져 있다. 민식이는 농장을 관리하기 위해 산봉우리마다 경비원를 배치하려 한다. 이를 위해 농장에 산봉우리가 총 몇 개 있는지를 세는 것이 문제다.

    산봉우리의 정의는 다음과 같다. 산봉우리는 같은 높이를 가지는 하나의 격자 혹은 인접한 격자들의 집합으로 이루어져 있다. (여기서 "인접하다"의 정의는 X좌표 차이와 Y좌표 차이 모두 1 이하일 경우로 정의된다.) 또한 산봉우리와 인접한 격자는 모두 산봉우리의 높이보다 작아야한다.

    문제는 격자 내에 산봉우리의 개수가 총 몇 개인지 구하는 것이다.

    입력

    첫째 줄에 정수 N(1 < N ≤ 100), M(1 < M ≤ 70)이 주어진다. 둘째 줄부터 N+1번째 줄까지 각 줄마다 격자의 높이를 의미하는 M개의 정수가 입력된다. 격자의 높이는 500보다 작거나 같은 음이 아닌 정수이다.

    출력

    첫째 줄에 산봉우리의 개수를 출력한다.

    Solved.ac 레벨

    골드 V

    풀이

    헷갈릴 부분이 있었던 그래프 탐색 문제.

     

    먼저 문제에서 세어야 하는 산봉우리에 대한 정의가 헷갈려서 시행착오가 좀 있었다.

    산봉우리는 같은 높이를 가지는 하나의 격자 혹은 인접한 격자들의 집합으로 이루어져 있다. (여기서 "인접하다"의 정의는 X좌표 차이와 Y좌표 차이 모두 1 이하일 경우로 정의된다.)

    나는 높이가 4인 격자와 높이가 3인 격자는 같은 산봉우리로 취급할 수 없는 줄 알았다. 하지만 인접한 격자들과 차이가 1이라면 한 개의 산봉우리로 셀 수 있다. X좌표와 Y 좌표 차이 모두 1 이하일 경우가 인접하다고 하였으므로 상, 하, 좌, 우 외에 대각선으로도 탐색이 가능하다. 즉 8방향으로 탐색이 가능하다.

    산봉우리와 "인접하다"를 그림으로 나타낸 것

    따라서 BFS를 돌리며 산봉우리가 형성될 수 있는지 아닌지를 판단하며, BFS가 끝난 후 산봉우리가 형성이 된다는 것이 확인되면 1개로 카운팅하면 된다.

     

    나는 이를 위해 bool 타입 flag 변수를 만들었고, 현재 탐색 시작점에서 8방향으로 탐색했을 때 현재 탐색 시작점보다 높은 격자가 존재하면 산봉우리가 아닌 것으로 판단해 flag를 flase로 바꿔주었다. 그 후 높이가 같은 격자만 탐색하도록 하였다.

     

    위의 그림에서 빨간색 산봉우리 구역을 예로 들면

    높이가 4인 지점 (0, 0)에서 높이가 같은 4인 것들만 탐색, 인접 격자들이 현재 탐색 시작점인 4보다 높이가 큰 격자가 없으므로 flag를 true로 바꿔주고 산봉우리로 카운팅해준다.

     

    그 다음으로는 3, 2, 1은 인접 격자가 다 자신의 높이 3, 2, 1보다 크므로 산봉우리로 카운팅하지 않는다. 높이가 4인 격자에 귀속된 산봉우리라는 뜻이다.

     

    Code

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n, m, cnt = 0;
    bool flag;
    pair<int, int> dir[8] = {{1, 0}, {1, 1},{0, 1},{-1, 1},{-1, 0}, {-1, -1}, {0, -1}, {1, -1}};
    int MAP[101][71];
    bool visited[101][71];
    queue<pair<int, int>> q;
    
    void BFS(int x, int y) {
        visited[x][y] = true;
        q.push({x, y});
    
        while(!q.empty()) {
            int curX = q.front().first;
            int curY = q.front().second;
            q.pop();
    
            for(int i = 0; i < 8; i++) {
                int nxtX = curX + dir[i].first;
                int nxtY = curY + dir[i].second;
    
                if(nxtX < 0 || nxtY < 0 || nxtX >= n || nxtY >= m) continue;
    
                if(MAP[x][y] < MAP[nxtX][nxtY]) flag = false;
                //현재 탐색의 기준이 되는 시작점보다 인접한 격자의 높이가 높다면 산봉우리가 아님
                //(가장 높은 격자에 귀속되는 산봉우리.)
    
                if(!visited[nxtX][nxtY] && MAP[x][y] == MAP[nxtX][nxtY]) {
                	//다음 격자를 방문하지 않았고, 높이가 같다면 탐색.
                    visited[nxtX][nxtY] = true;
                    q.push({nxtX, nxtY});
                }
            }
        }
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        cin >> n >> m;
    
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                cin >> MAP[i][j];
            }
        }
    
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
                if(!visited[i][j]){
                    flag = true;
                    BFS(i, j);
                    if(flag) cnt++;
                    //BFS 탐색 결과 산봉우리일 경우 (산봉우리의 가장 높은 지점일 경우) 카운팅.
                }
            }
        }
    
        cout << cnt << "\n";
    
    
        return 0;
    }

    연휴동안은 여행 때문에 브론즈 V와 브론즈 IV 문제들로 스트릭만 채워서... 4일만에 다시 머리 쓰려니 너무 적응이 안 된다.

     

    1245번: 농장 관리

    첫째 줄에 정수 N(1 < N ≤ 100), M(1 < M ≤ 70)이 주어진다. 둘째 줄부터 N+1번째 줄까지 각 줄마다 격자의 높이를 의미하는 M개의 정수가 입력된다. 격자의 높이는 500보다 작거나 같은 음이 아닌 정수

    www.acmicpc.net

     

Designed by Tistory.