문제링크
https://www.acmicpc.net/problem/2667
문제설명
문제
<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여기서 연결되었다는 것은 어떤 집이 좌우, 혹은 아래위로 다른 집이 있는 경우를 말한다. 대각선상에 집이 있는 경우는 연결된 것이 아니다. <그림 2>는 <그림 1>을 단지별로 번호를 붙인 것이다. 지도를 입력하여 단지수를 출력하고, 각 단지에 속하는 집의 수를 오름차순으로 정렬하여 출력하는 프로그램을 작성하시오.
입력
첫 번째 줄에는 지도의 크기 N(정사각형이므로 가로와 세로의 크기는 같으며 5≤N≤25)이 입력되고, 그 다음 N줄에는 각각 N개의 자료(0혹은 1)가 입력된다.
출력
첫 번째 줄에는 총 단지수를 출력하시오. 그리고 각 단지내 집의 수를 오름차순으로 정렬하여 한 줄에 하나씩 출력하시오.
제한사항
제한시간 | 메모리제한 |
1 초 | 128MB |
출처 - www.acmicpc.net
문제풀이
👨🏻💻 핵심 스킬 👨🏻💻
DFS, 연결요소
단지번호붙이기 문제는 지도에 표시되어있는 집의 상태를 확인하여 단지를 매겨주어 단지의 수와 각 단지별 집의 수를 정렬하여 출력해주는 문제입니다. 단지를 매기는 기준은 가로 혹은 세로로 동일한 집이 있을 경우이며, 지도에서는 집이 있다면 1 없다면 0으로 표시해줍니다.
이를 해결하기 위해 지도에 표시되어있는 1로 이루어진 한 값들을 각각 정점이라고 생각해주었습니다. 각 정점마다 연결되는 간선은 가로와 세로의 1로 표기되어있는 값들 이라고 생각해주면 됩니다.
이렇게 집이 있다고 가정을하겠습니다. 1행 1열 정점과 연결된 간선은 아래인 2행 1열이 됩니다. 2행 1열의 정점은 1행 1열, 2행 2열, 3행 1열의 정점과 연결되어있다고 알 수 있습니다. 그리고 항상 정점이 연결되어있는지 확인할 때는 상하좌우를 모두 확인해주어 0일 경우 연결이 되어있지 않다고 생각하여주고 1일 경우 연결이 되어있다고 생각하고 체크가 안되어 있을 경우 dfs로 불러주면 됩니다.
dfs를 사용하면 연결되어있는 정점들을 모두 한번씩 확인해주기 때문에 각 정점에서 1씩만 리턴값으로 넘겨주어 더해주면 최종적으로 단지에 속해있는 집의 수를 구할 수 있게 됩니다. 그리고 dfs로 체크를 하고 아직 체크가 되어있지 않은 값들은 0이거나 혹은 다른 연결요소(단지)이기 때문에 추가로 체크하여 단지일 경우 ArrayList를 사용하여 넣어주면 됩니다.
결과적으로 모든 정점을 확인한 ArrayList에는 모든 단지에 대한 집 수가 들어가 있을 것 이므로 이를 정렬하여 출력하면 문제를 해결 할 수 있습니다.
구현코드
package backjoon_2667;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] map = new int[n][n];
for (int i = 0; i < n; i++) {
String line = sc.next();
for (int j = 0; j < n; j++) {
map[i][j] = line.charAt(j) - '0';
}
}
boolean[][] checked = new boolean[n][n];
ArrayList<Integer> result = new ArrayList<>();
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j ++){
if(!checked[i][j]){
int dfs = dfs(i,j,checked,map);
if(dfs != 0)
result.add(dfs);
}
}
}
Collections.sort(result);
System.out.println(result.size());
for(int i = 0; i < result.size(); i++)
System.out.println(result.get(i));
}
public static int dfs(int x, int y, boolean[][] checked, int[][] map) {
checked[x][y] = true;
int count = map[x][y];
if (count == 1) {
if (x - 1 >= 0 && !checked[x - 1][y]) {
count += dfs(x - 1, y, checked, map);
}
if (y - 1 >= 0 && !checked[x][y - 1]) {
count += dfs(x,y-1,checked,map);
}
if (x + 1 < checked.length && !checked[x + 1][y]) {
count += dfs(x+1,y,checked,map);
}
if (y + 1 < checked.length && !checked[x][y + 1]) {
count += dfs(x,y+1,checked,map);
}
}
return count;
}
}
시간복잡도
$O(V+E)$
'CodingTest > Backjoon' 카테고리의 다른 글
[BOJ_7562] 나이트의 이동 (Java) (0) | 2021.12.16 |
---|---|
[BOJ_7576] 토마토 (java) (0) | 2021.12.16 |
[BOJ_1707] 이분그래프 (java) (0) | 2021.12.15 |
[BOJ_11724] 연결요소 (java) (0) | 2021.12.14 |
[BOJ_2156] 포도주 시식 (java) (0) | 2021.11.28 |