눈금의 간격이 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 리스트를 오름차순으로 정렬하고, 영역의 개수와 각 영역의 넓이를 출력한다.