Codeup 4421 BaekJoon 2667 단지번호 붙이기
Ex) 첫 번째 줄에는 총 단지수를 출력하시오. 그리고 각 단지내 집의 수를 오름차순으로 정렬하여 한 줄에 하나씩 출력하시오
- <그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다.
- 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다.
- 여기서 연결되었다는 것은 어떤 집이 좌우, 혹은 아래위로 다른 집이 있는 경우를 말한다.
- 대각선상에 집이 있는 경우는 연결된 것이 아니다. <그림 2>는 <그림 1>을 단지별로 번호를 붙인 것이다.
- 지도를 입력하여 단지수를 출력하고, 각 단지에 속하는 집의 수를 오름차순으로 정렬하여 출력하는 프로그램을 작성하시오.
- 첫 번째 줄에는 지도의 크기 N(정사각형이므로 가로와 세로의 크기는 같으며 5≤N≤25)이 입력되고 그 다음 N줄에는 각각 N개의 자료(0혹은 1)가 입력된다.

MySol) 224ms
<hide/>
// 단지번호 붙이기
import java.util.ArrayList;
import java.util.Scanner;
/*
입출력예시
7
0110100
0110101
1110101
0000111
0100000
0111110
0111000
3
7
8
9
*/
public class Practice1 {
static int MAX_COUNT = 100;
static int[][] AdjMat = new int[MAX_COUNT][MAX_COUNT];
static int[][] Visited = new int[MAX_COUNT][MAX_COUNT];
static int Width = 0;
static int[][] DirMat = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
static int idx = 0;
static ArrayList<Integer> result = new ArrayList<>();
static int cnt = 0; // 각 영역의 개수
public static void DFS(int _currRow, int _currCol){
Visited[_currRow][_currCol] = 1;
++cnt;
for(int i = 0; i < 4; ++i){
int nextRow = _currRow + DirMat[i][0];
int nextCol = _currCol + DirMat[i][1];
if( nextRow <= 0 || nextRow > Width ||
nextCol <= 0 || nextCol > Width){
continue;
}
if(AdjMat[nextRow][nextCol] == 1 && Visited[nextRow][nextCol] == 0){ // 같은 단지 내에서 DFS실행
DFS(nextRow, nextCol);
}
}
}
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
Width = scan.nextInt();
for(int i = 1; i <= Width; ++i){
String str = scan.next();
for(int j = 1; j <= Width; ++j){
AdjMat[i][j] = str.charAt(j - 1) - 48;
}
}
/*
인접행렬 확인
for(int i = 1; i <= Width; ++i){
for(int j = 1; j <= Width; ++j){
System.out.print(AdjMat[i][j] + " ");
}
System.out.println();
}
*/
for(int i = 1; i <= Width; ++i){
for(int j = 1; j <= Width; ++j){
if(AdjMat[i][j] == 1 && Visited[i][j] == 0){
DFS(i, j);
++idx;
}
if(cnt > 0){ // 어떤 영역의 DFS을 다 돌고 나면 초기화해준다.
result.add(cnt);
cnt = 0;
}
}
}
System.out.println(idx); // 단지의 개수
result.sort((x, y) -> x - y); // 오름차순
for(int r: result){
System.out.println(r); //면적의 개수 정렬
}
}
}
- 결과 배열 처리하는 것 때문에 에러가 나고 복잡해져서(배열 사이즈 문제) 결괏값을 ArrayList에 저장하니까 해결됐다.
- 전에 작성했던 아래의 코드에서는 영역마다 배열에 영역 사이즈를 넣으려다가 오류가 났다.
-> 그런데, 모든 영역을 방문하기 전까지 resultArea[] 의 사이즈를 알 수 없기 때문에 문제가 생겼다.
-> 따라서, 배열에 비해서 사이즈에 유동적인 List를 활용하면 좋다.
- 지난 번에 풀 때 cnt 처리하는 부분에서 헤멨다. nextRow, nextCol을 찾은 경우에만 cnt++을 했더니 배열원소들이 내가 찾는 값보다 모두 1씩 작았다. (맨 처음 실행되는 DFS를 카운트하지 않아서 )
- 메서드 간에 실행 순서를 꼭 파악해야겠다.
참고) 프로그래머스의 컬러링북 색칠하기와 유사하다.
https://school.programmers.co.kr/learn/courses/30/lessons/1829
https://oranthy.tistory.com/261
========================오류 코드========================
코드업에서는 정답인데 백준에서는 채점 41% 쯤에 ArrayIndexOutOfBounds가 발생한다. 오류 수정이 필요한다.
<hide/>
import java.util.Arrays;
import java.util.Scanner;
public class HouseNumbering {
static int MAX_COUNT = 100;
static int[][] AdjMat = new int[MAX_COUNT][MAX_COUNT];
static int[][] Visited = new int[MAX_COUNT][MAX_COUNT];
static int Width = 0;
static int[][] DirMat = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
static int idx = 0;
static int[] resultArr = new int[MAX_COUNT];
public static void DFS(int _currRow, int _currCol){
Visited[_currRow][_currCol] = 1;
for(int i = 0; i < 4; ++i){
int nextRow = _currRow + DirMat[i][0];
int nextCol = _currCol + DirMat[i][1];
if(Visited[nextRow][nextCol] == 1 ||
nextRow <= 0 || nextRow > Width ||
nextCol <= 0 || nextCol > Width){
continue;
}
if(AdjMat[nextRow][nextCol] == 1){ // 같은 단지 내에서 DFS실행
++resultArr[idx];
System.out.printf("(%d, %d) -> (%d, %d)%n", _currRow, _currCol, nextRow, nextCol);
DFS(nextRow, nextCol);
}
}
}
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
Width = scan.nextInt();
for(int i = 1; i <= Width; ++i){
String str = scan.next();
for(int j = 1; j <= Width; ++j){
AdjMat[i][j] = str.charAt(j - 1) - 48;
}
}
// 인접행렬 확인
// for(int i = 1; i <= Width; ++i){
// for(int j = 1; j <= Width; ++j){
// System.out.print(AdjMat[i][j] + " ");
// }
// System.out.println();
// }
for(int i = 1; i <= Width; ++i){
for(int j = 1; j <= Width; ++j){
if(AdjMat[i][j] == 1 && Visited[i][j] == 0){
DFS(i, j);
++idx;
}
}
}
System.out.println(idx);
for(int i = 0; i < idx; ++i){
resultArr[i] += 1;
}
int[] res = new int[idx]; // 2
for(int i = 0; i < idx; ++i){
res[i] = resultArr[i]; // 7 5
}
Arrays.sort(res); // 5 7
for(int r : res){
System.out.println(r);
}
}
}
Note)
- 인접행렬의 값들이 붙어서 입력이 된다.
-> 따라서 String으로 입력 받는다.
-> str.charAt(j - 1) - 48;
- DFS 코드 안에서 새롭게 재귀함수가 돌아갈 때마다 resultArr[]의 값을 1씩 늘린다.
-> resultArr[0]의 값이 7일 때 재귀함수는 6번 실행이 된다.
-> 따라서, 마지막에 배열의 모든 값을 1씩 증가시켜줘야한다.
- index(영역의 개수)는 main함수에서 DFS가 끝날 때마다 증가시킨다.
<hide/>
[입력]
7
0110100
0110101
1110101
0000111
0100000
0111110
0111000
[출력]
3
7
8
9
[입력]
5
11100
01000
11010
01010
00111
[출력]
2
5
7
출처: https://codeup.kr/problem.php?id=4421
단지 번호 붙이기
문제1) <그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집들의 모임인 단지를 정의하고, 단지에 번호를 붙이려
codeup.kr
https://www.acmicpc.net/problem/2667
2667번: 단지번호붙이기
<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여
www.acmicpc.net