[백준] 2583번 영역 구하기

Peace·2021년 1월 22일

[백준] 2583번 영역 구하기

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

문제

눈금의 간격이 1인 M×N(M,N≤100)크기의 모눈종이가 있다. 이 모눈종이 위에 눈금에 맞추어 K개의 직사각형을 그릴 때, 이들 K개의 직사각형의 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어진다.

예를 들어 M=5, N=7 인 모눈종이 위에 <그림 1>과 같이 직사각형 3개를 그렸다면, 그 나머지 영역은 <그림 2>와 같이 3개의 분리된 영역으로 나누어지게 된다.

M, N과 K 그리고 K개의 직사각형의 좌표가 주어질 때, K개의 직사각형 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어지는지, 그리고 분리된 각 영역의 넓이가 얼마인지를 구하여 이를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오른쪽 위 꼭짓점의 x, y좌표값이 빈칸을 사이에 두고 차례로 주어진다. 모눈종이의 왼쪽 아래 꼭짓점의 좌표는 (0,0)이고, 오른쪽 위 꼭짓점의 좌표는(N,M)이다. 입력되는 K개의 직사각형들이 모눈종이 전체를 채우는 경우는 없다.

출력

첫째 줄에 분리되어 나누어지는 영역의 개수를 출력한다. 둘째 줄에는 각 영역의 넓이를 오름차순으로 정렬하여 빈칸을 사이에 두고 출력한다.

문제 이해

문제가 사각형을 주어줬다. 하지만, 사각형으로 하면 문제가 좀 복잡해지고 어려워진다. 그래서 나는 사각형 대신 좌표하나가 한 사각형이라고 생각을 하고 문제를 풀었다. 문제를 풀 때는 전혀 문제가 되지 않는다.
모눈종이에서 사각형이 있지 않은 부분 중 사각형에 의해 나눠져있는 곳들의 개수와 크기를 구하는 문제이다.

문제 접근

  1. 입력
  2. 사각형이 있는 부분을 1로 표시해주기
  3. search 시작 전 0인 부분을 찾으면, count + 1 해주기.
  4. 0으로 표시된 부분을 dfs를 이용하여, search를 진행하고 search한 부분은 1로 표시.
  5. search하면서 자신의 branch를 다 체크했다면, size + 1 해준다.
  6. 자신이 속해 있는 sub-graph의 dfs를 다 진행했다면, size를 vector에 넣어주기.
  7. 위 과정이 다 끝나면, vector를 오름차순으로 sort해주기.
  8. 출력

코드 구현(c++)

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
int X, Y, rectNum;
int map[101][101];

int xCheck[4] = {-1,0,0,1};
int yCheck[4] = {0,-1,1,0};
int cnt;
int rectSize;
vector<int> rectSizes;

void makeRect(int x1, int y1, int x2, int y2){
    for(int i = y1 ; i < y2 ; i++){
        for(int j = x1 ; j < x2 ; j++){
            map[i][j] = 1;
        }
    }
}

void search(int x, int y){
    int nextX, nextY;
    for(int i = 0 ; i < 4 ; i++){
        nextX = x + xCheck[i]; nextY = y + yCheck[i];
        if(nextX >= 0 && nextX < X && nextY >= 0 && nextY < Y && map[nextY][nextX] == 0){
            map[nextY][nextX] = 1;
            search(nextX, nextY);
        } 
    }
    rectSize++;
}

void dfs(){
    for(int i = 0 ; i < Y ; i++){
        for(int j = 0 ; j < X ; j++){
            if(map[i][j] == 0){
                cnt++;
                map[i][j] = 1;
                search(j,i);
                rectSizes.push_back(rectSize);
                rectSize = 0;
            }
        }        
    }
}

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

    cin >> Y >> X >> rectNum;
    int x1, x2, y1, y2;
    for(int i = 0 ; i < rectNum ; i++){
        cin >> x1 >> y1 >> x2 >> y2;
        makeRect(x1, y1, x2, y2);
    }
    cnt = 0;
    dfs();
    sort(rectSizes.begin(), rectSizes.end());
    cout << cnt << "\n";
    for(int i = 0 ; i < rectSizes.size() ; i++){
        cout << rectSizes[i] << " ";
    }
    cout << "\n";
}

평가

문제를 꼭 주어진 대로만 풀면 복잡해지는 경우가 있다. 문제를 단순화 시킬 수 있다면 단순화 시켜서 문제를 다르게 접근하는 것도 하나의 방법인 것 같다.

profile
https://peace-log.tistory.com 로 이사 중

2개의 댓글

comment-user-thumbnail
2021년 1월 23일

이 문제 넘 어려워요ㅠ
코드 작성할 때 ‘’’C++
//code
‘’’로 감싸주시면 색이 입혀집니다!

1개의 답글