2667 단지번호붙이기
문제 해석
가로 세로 크기가 5에서 25사이의 정사작형 배열에서 1이 뭉쳐져있는 구역을 구하고, 각 구역에서 1이 몇개나 있는지 오름차순으로 출력하라는 문제입니다.
1이 상하좌우에 있다면 그것은 같은 그룹에 속합니다. 아래 사진을 보세요.
<그림 1>에서 1의 그룹은 새 개의 구역으로 <그림 2>로 표현될 수 있습니다. 1번 그룹, 2번 그룹, 3번 그룹이 있고, 각각의 그룹은 7, 8, 9개의 1이 뭉쳐져있는 것이죠.

입력은 가로, 세로의 길이가 주어지고, 위의 그림처럼 띄어지지 않은 문자열형태로 넘어옵니다. 이렇게 말이죠.
7
0110100
0110101
1110101
0000111
0100000
0111110
0111000
출력은 그룹의 갯수와 각 그룹이 포함하고 있는 1의 개수를 오름차순으로 출력합니다.
3 (그룹 개수)
7 (각 그룹이 포함하고 있는 1을 오름차순으로 출력)
8
9
풀이
DFS(Depth First Search)를 이용하면 쉽게 풀 수 있습니다. 우선 입력이 불친절하게 들어오니까 이를 정수형 배열로 바꾸어줍니다. 제가 문자 배열은 왠만하면 사용하기 싫거든요.
scanf("%d", &n);
for (int i = 0; i < n; i++) {
char line[MAX_N];
scanf("%s", line);
for (int j = 0; j < n; j++)
map[i][j] = line[j] - '0';
}배열의 길이 n을 입력받은 후에 for루프를 n번 돌면서 문자 배열 line으로 배열의 한줄을 입력받습니다. 그 for문의 내부 for문에서는 map배열에 실제 입력을 시킵니다. 그래서 map에는 입력들을 정수형 배열로 입력됩니다.
int cnt = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (map[i][j] == 1) {
groups[cnt]=dfs(i, j);
cnt = cnt + 1;
}입력을 받았으면 map을 전부 이중for문으로 돌며 1이 있는 부분에서 멈춥니다. 1이 있는 부분에서 멈추게 되면 그 지점에서 dfs를 호출하는 것이죠. dfs가 몇번 호출이 되느냐에 따라서 cnt가 커지게 됩니다. 바로 cnt가 그룹의 전체 갯수를 나타냅니다.
groups에는 cnt라는 그룹에 몇개의 1이 포함이 되어있는지 저장됩니다.
dfs에서 무슨 동작을 할까요? 이 문제를 풀기위한 핵심인 dfs를 보도록합시다.
int dfs(int y, int x) {
if (y < 0 || x < 0 || y >= n || x >= n || map[y][x] == 0) return 0;
map[y][x] = 0;
return 1 + dfs(y + 1, x) + dfs(y - 1, x)
+dfs(y, x + 1) + dfs(y, x - 1);
}
dfs함수는 바로 위와 같이 정의되어 있습니다. y는 행, x는 열만을 인자로 받아들이고 있습니다. y나 x가 배열 범위 밖에 있다면 더이상 dfs를 호출하지 않습니다. 또는 map[y][x]가 0인 부분도 기저사례에 포함이 됩니다. 지금까지 말했던 것들이 첫번째 if문의 조건이 되겠네요.
배열 범위에 포함이 되어있으며 map[y][x]=1이라면 바로 그 지점을 0으로 바꿔줍니다. 왜 바꿔주냐면 더 이상 이 점을 방문할 필요가 없으니까요. 만약 map[y][x]=0이 없다면 이 프로그램은 영원히 끝나지 않을겁니다.
그 후에는 상(y-1)하(y+1)좌(x-1)우(x+1)에 dfs를 호출합니다. return에 1을 더해야만 최종 dfs에는 그룹의 1의 개수가 return됩니다.
printf("%d\n", cnt);
sort(groups, groups + cnt);
for (int i = 0; i < cnt; i++)
printf("%d\n",groups[i]);
이제 답은 전부 구했네요. cnt를 출력하고 오름차순으로 1의 개수를 출력하라 하였으니 정렬 후에 groups를 출력하면 됩니다.
아래는 전체코드입니다.
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
#define MAX_N 26
int n;
int map[MAX_N][MAX_N];
int groups[MAX_N*MAX_N];
int dfs(int y, int x) {
if (y < 0 || x < 0 || y >= n || x >= n || map[y][x] == 0) return 0;
map[y][x] = 0;
return 1 + dfs(y + 1, x) + dfs(y - 1, x)
+dfs(y, x + 1) + dfs(y, x - 1);
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
char line[MAX_N];
scanf("%s", line);
for (int j = 0; j < n; j++)
map[i][j] = line[j] - '0';
}
int cnt = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (map[i][j] == 1) {
groups[cnt]=dfs(i, j);
cnt = cnt + 1;
}
printf("%d\n", cnt);
sort(groups, groups + cnt);
for (int i = 0; i < cnt; i++)
printf("%d\n",groups[i]);
return 0;
}
dfs만 알면 그리 어렵지 않게 풀수 있는 문제였습니다.
'알고리즘 > DFS' 카테고리의 다른 글
| [DFS] 위상정렬(Topological Sort)의 세부 설명 및 코드(C++) (0) | 2021.03.11 |
|---|---|
| [그래프] 이분 매칭(bipartite matching)의 설명과 코드, 예제 (0) | 2021.03.06 |
| [알고리즘] 백준 온라인 저지 BOJ 1260 DFS와 BFS (0) | 2018.09.19 |
| [알고리즘 DFS] 백준 온라인 저지 (BOJ) 1012 유기농 배추 (0) | 2018.09.18 |
| [알고리즘 : 그래프 이론] 그림으로 쉽게 보는 DFS 기본, 개념, 설명, 코드 (0) | 2018.09.12 |