99클럽 코테 스터디 35일차 TIL | 영역 구하기

fever·2024년 8월 25일
0

99클럽 코테 스터디

목록 보기
35/42
post-thumbnail

🖥️ 문제

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

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

<그림 2>와 같이 분리된 세 영역의 넓이는 각각 1, 7, 13이 된다.

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

📝 풀이

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

public class Main {
    static boolean[][] visited;
    static List<Integer> areaSizes;
    static int currentAreaSize;
    static int rows;
    static int cols;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        rows = Integer.parseInt(st.nextToken());
        cols = Integer.parseInt(st.nextToken());
        int rectangleCount = Integer.parseInt(st.nextToken());

        visited = new boolean[rows][cols];
        areaSizes = new ArrayList<>();

        // 직사각형들의 영역을 방문 처리
        for (int i = 0; i < rectangleCount; i++) {
            st = new StringTokenizer(br.readLine());
            int startX = Integer.parseInt(st.nextToken());
            int startY = Integer.parseInt(st.nextToken());
            int endX = Integer.parseInt(st.nextToken()) - 1;
            int endY = Integer.parseInt(st.nextToken()) - 1;

            for (int y = startY; y <= endY; y++) {
                for (int x = startX; x <= endX; x++) {
                    visited[y][x] = true;
                }
            }
        }

        // 영역 탐색
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                if (!visited[y][x]) {
                    currentAreaSize = 0;
                    dfs(y, x);
                    areaSizes.add(currentAreaSize);
                }
            }
        }

        // 결과 출력
        Collections.sort(areaSizes);
        StringBuilder sb = new StringBuilder();
        sb.append(areaSizes.size()).append("\n");
        for (int size : areaSizes) {
            sb.append(size).append(" ");
        }
        System.out.print(sb);
    }

    static void dfs(int y, int x) {
        visited[y][x] = true;
        currentAreaSize++;

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

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

            if (ny >= 0 && ny < rows && nx >= 0 && nx < cols && !visited[ny][nx]) {
                dfs(ny, nx);
            }
        }
    }
}

이 문제는 2차원 평면에서 직사각형들이 차지하지 않은 영역들을 찾고, 각 영역의 넓이를 계산하는 그래프 탐색 문제다.

먼저, 직사각형의 좌표 정보를 입력받아 visited라는 2차원 boolean 배열을 생성한다. (배열의 크기는 모눈종이의 크기인 rows × cols)
그리고 각 직사각형의 좌표를 받아, 그 범위 내의 모든 칸을 true로 설정한다. 이렇게 설정된 칸은 직사각형이 차지한 영역으로 더 이상 탐색하지 않는다.

이후 모눈종이 전체를 순회하면서, 아직 방문하지 않은 (visited가 false인) 영역을 발견할 때마다 DFS 탐색을 시작한다. 이때 탐색이 진행될 때마다 영역의 넓이(currentAreaSize)를 증가시켰다.

DFS는 재귀적으로 인접한 모든 빈 칸을 방문하며, 한 번의 DFS 호출이 끝나면 하나의 분리된 영역이 완성된다. 이후 각 영역의 넓이는 areaSizes 리스트에 저장된다.

모든 탐색이 완료되면 areaSizes 리스트를 오름차순으로 정렬하고, 영역의 개수와 각 영역의 넓이를 출력한다.

profile
선명한 삶을 살기 위하여

0개의 댓글