문제 요약
https://www.acmicpc.net/problem/2583
도화지의 크기와 그 위에 그려진 K개의 직사각형이 주어질 때 직사각형을 제외한 나머지 빈 영역의 개수와 각 영역의 넓이를 구하는 문제입니다.
- 도화지는 M × N 크기의 2차원 배열로 표현됩니다.
- 좌표는 (x1, y1) ~ (x2, y2) 형태로 주어지며, 왼쪽 아래가 시작점, 오른쪽 위가 끝점입니다.
- 직사각형이 채워진 영역은 1로 표시하고, 나머지 빈 영역은 0입니다.
- 0인 영역끼리 인접한 곳을 하나의 영역으로 간주합니다.
(상하좌우 연결된 경우만 인접)
출력:
- 빈 영역의 개수
- 각 영역의 넓이 (오름차순)
전체 코드
import java.util.*;
class Point {
public int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public class Main {
static int[] dx = {-1, 0, 1, 0};
static int[] dy = {0, 1, 0, -1};
static int n, m;
public void BFS(int[][] arr) {
Queue<Point> q = new LinkedList<>();
int count = 0;
ArrayList<Integer> answer = new ArrayList<>();
for(int x=0; x<n; x++) {
for(int y=0; y<m; y++) {
if(arr[x][y]==0) {
arr[x][y] = 1;
count++;
int area = 1;
q.offer(new Point(x, y));
while(!q.isEmpty()) {
Point tmp = q.poll();
for(int i=0; i<4; i++) {
int nx = tmp.x + dx[i];
int ny = tmp.y + dy[i];
if(nx>=0 && nx<n && ny>=0 && ny<m && arr[nx][ny]==0) {
arr[nx][ny] = 1;
q.offer(new Point(nx, ny));
area++;
}
}
}
answer.add(area);
}
}
}
System.out.println(count);
Collections.sort(answer);
for(int i=0; i<answer.size(); i++) System.out.print(answer.get(i)+" ");
}
public static void main(String[] args) {
Main T = new Main();
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
int[][] arr = new int[n][m];
int k = sc.nextInt();
for(int i=0; i<k; i++) {
int lx = sc.nextInt();
int ly = sc.nextInt();
int rx = sc.nextInt();
int ry = sc.nextInt();
for(int row=ly; row<ry; row++) {
for(int col=lx; col<rx; col++) {
arr[row][col] = 1;
}
}
}
T.BFS(arr);
sc.close();
}
}
코드 설명
static int[] dx = {-1, 0, 1, 0};
static int[] dy = {0, 1, 0, -1};
- 4방향 이동을 위한 배열 (상, 우, 하, 좌)
for (int row = ly; row < ry; row++) {
for (int col = lx; col < rx; col++) {
arr[row][col] = 1;
}
}
- 입력된 직사각형 영역을 1로 채움
- y좌표가 행(row), x좌표가 열(col)과 매핑됨에 주의
if (arr[x][y] == 0) {
arr[x][y] = 1;
count++;
int area = 1;
q.offer(new Point(x, y));
- 0인 좌표에서 BFS 시작
- 시작 지점을 1로 바꿔 방문 체크 후 큐에 삽입
- area는 현재 영역의 넓이
while (!q.isEmpty()) {
Point tmp = q.poll();
for (int i = 0; i < 4; i++) {
int nx = tmp.x + dx[i];
int ny = tmp.y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && arr[nx][ny] == 0) {
arr[nx][ny] = 1; // 방문 체크
q.offer(new Point(nx, ny));
area++;
}
}
}
- BFS로 상하좌우 인접한 0인 곳을 계속 방문
- 방문 시마다 넓이 +1, 그리고 방문 체크
Collections.sort(answer);
System.out.println(count);
for (int a : answer) System.out.print(a + " ");
- 넓이 리스트 정렬 후 출력
시간 복잡도 분석
- 직사각형 채우기 : O(K × 면적)
- BFS 탐색 : O(N × M)
- 전체 반복문 : O(N × M)
- 정렬 : O(A log A) (A = 영역 수 ≤ N×M)
- 총 시간 복잡도: O(N × M + A log A)
'코딩테스트 > 백준' 카테고리의 다른 글
| 백준 2580 스도쿠 (Java, DFS 백트래킹) (0) | 2025.06.20 |
|---|---|
| 백준 4949번 균형잡힌 세상(Java, Stack) (0) | 2025.06.18 |
| 백준 1987번 알파벳 (Java, DFS) (0) | 2025.06.18 |
| 백준 1759 암호 만들기 (Java, DFS) (1) | 2025.06.18 |
| 백준 2667번 - 단지번호붙이기 (Java, BFS) (1) | 2025.06.17 |