그림
https://www.acmicpc.net/problem/1926
1) 문제
어떤 큰 도화지에 그림이 그려져 있을 때, 그 그림의 개수와 가장 넓은 그림의 넓이를 출력하여라.
그림은 1로 연결된 영역이고, 가로나 세로로만 연결된 것을 연결된 것이라 한다.
그림의 넓이는 1의 개수이다.
그림은 1로 연결된 영역이고, 가로나 세로로만 연결된 것을 연결된 것이라 한다.
그림의 넓이는 1의 개수이다.
입력: 세로 크기 n (1 ≤ n ≤ 500), 가로 크기 m (1 ≤ m ≤ 500)
이후 n줄에 걸쳐 0과 1로 이루어진 도화지 정보 제공
출력: 그림의 개수와 가장 넓은 그림의 넓이 (없으면 0)
이후 n줄에 걸쳐 0과 1로 이루어진 도화지 정보 제공
출력: 그림의 개수와 가장 넓은 그림의 넓이 (없으면 0)
2) 예시
입력 | 출력 |
---|---|
6 5 1 1 0 1 1 0 1 1 0 0 0 0 0 0 0 1 0 1 1 1 0 0 1 1 1 0 0 1 1 1 |
4 9 |
3) 풀이
1. 아이디어
2중 for문으로 모든 좌표 순회 → 값이 1이면서 방문하지 않았으면 BFS 실행
BFS 돌 때마다 그림 개수 +1, 넓이를 계산해 최대값 갱신
2. 시간복잡도
BFS는 O(V + E)이며,
V: 최대 500*500, E: 각 정점당 최대 4방향 연결이므로 E = 4V
최대 O(5 * 250,000) = 1,250,000 → 충분히 가능
(코딩테스트는 2초간 2억번정도는 허용된 연산량)
3. 자료구조
- 그래프 지도: int[][]
- 방문 확인: boolean[][]
- 탐색용 큐: Queue
4) 코드
import java.util.*;
public class Main {
static int n, m;
static int[][] graph;
static boolean[][] visited;
static int[] dx = {1, -1, 0, 0};
static int[] dy = {0, 0, 1, -1};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
graph = new int[n][m];
visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
graph[i][j] = sc.nextInt();
}
}
int count = 0;
int maxArea = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (!visited[i][j] && graph[i][j] == 1) {
count++;
maxArea = Math.max(maxArea, bfs(i, j));
}
}
}
System.out.println(count);
System.out.println(maxArea);
}
static int bfs(int x, int y) {
Queue<int[]> queue = new LinkedList<>();
queue.offer(new int[]{x, y});
visited[x][y] = true;
int area = 1;
while (!queue.isEmpty()) {
int[] cur = queue.poll();
int cx = cur[0];
int cy = cur[1];
for (int i = 0; i < 4; i++) {
int nx = cx + dx[i];
int ny = cy + dy[i];
if (nx >= 0 && ny >= 0 && nx < n && ny < m) {
if (!visited[nx][ny] && graph[nx][ny] == 1) {
visited[nx][ny] = true;
queue.offer(new int[]{nx, ny});
area++;
}
}
}
}
return area;
}
}
주석으로 설명
import java.util.*;
//자바 유틸을 가져와 queue, Scanner를 사용할 수 있게함
public class Main {
// 자바는 클래스단위로 실행되니, Main 클래스 정의
// 아래 변수들은 다른 메소드에서 사용할 수 있게 static으로 선언
static int m, n;
// 도화지의 가로 m, 세로n
static int[][] graph;
// 도화지의 전체상태를 저장할 이차원배열 (0: 빈칸, 1: 그림)
static boolean[][] visited;
// 이미 방문한 칸인지를 저장하는 배열, x,y좌표가 들어가게해서 이차원배열
static int[] dx = {1, -1, 0, 0};
static int[] dy = {0, 0, 1, -1};
// 하상우좌로 이동시키기위한 배열을 선언
public static void main(String[] args) {
// 자바의 시작점인 메인메서드
Scanner sc = new Scanner(System.in);
// 입력을 위한 스캐너 객체 생성
n = sc.nextInt();
m = sc.nextInt();
// 가로m과 세로n을 입력받음
graph = new int[n][m];
visited = new boolean[n][m];
// 도화지 및 방문여부 상태를 초기화
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
graph[i][j] = sc.nextInt();
}
}
// 이중반복문을 이용하여 도화지의 상태(0또는1)를 저장함
int count = 0;
int maxArea = 0;
// 그림의 개수와 가장 넓은 그림의 넓이를 선언
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// 이중반복문으로 전체 도화지를 순회
if (!visited[i][j] && graph[i][j] == 1) {
// 방문하지 않은 그림이 있는 곳이라면 (BFS 조건)
count++;
// 그림의 개수를 1 증가시킴
maxArea = Math.max(maxArea, bfs(i, j));
// bfs 메소드로 현재 그림의 넓이를 구하고 지금까지 넓이와 비교하여 갱신
}
}
}
System.out.println(count);
System.out.println(maxArea);
// count와 maxArea 출력
}
static int bfs(int x, int y) {
//BFS 탐색을 위한 메소드
Queue<int[]> queue = new LinkedList<>();
//BFS를 위한 Queue선언, int[]은 x,y좌표 배열
queue.offer(new int[]{x, y});
visited[x][y] = true;
// 시작좌표를 큐에 넣고, 방문한 것으로 처리함
int area = 1;
// 현재 그림의 넓이를 1로 초기화
while (!queue.isEmpty()) {
// queue가 빌때까지 계속 반복함
int[] cur = queue.poll();
int cx = cur[0];
int cy = cur[1];
// 큐에서 현재 좌표를 꺼냄
for (int i = 0; i < 4; i++) {
int nx = cx + dx[i];
int ny = cy + dy[i];
// 상하좌우 이동할 새좌표를 계산
if (nx >= 0 && ny >= 0 && nx < n && ny < m) {
// 배열의 범위를 벗어나지않은경우(즉, 길이가 음수가 아니고 가로세로안)
if (!visited[nx][ny] && graph[nx][ny] == 1) {
// 방문하지 않았고, 그림이 있는 경우
visited[nx][ny] = true;
queue.offer(new int[]{nx, ny});
area++;
// 큐에 넣고 방문처리하고, 넓이를 1 증가시킴
}
}
}
}
return area;
//그림의 넓이를 반환함
}
}
5) 리뷰
BFS 문제를 처음 접하는데 기본을 배우기 좋은 문제였다.
'Baekjoon Coding Test > Java' 카테고리의 다른 글
[백준 15649] Java - N과 M (1) (0) | 2025.05.03 |
---|---|
[백준 10870] Java - 피보나치 수 5 (0) | 2025.05.02 |