4963 섬의 개수
4963 섬의 개수
4방향 탐색이 아닌 8방향 탐색문제
대각선으로도 이동할 수 있다
https://www.acmicpc.net/problem/4963
1. 문제
간단 설명
섬의 개수를 세는 문제
기존의 2667 단지번호붙이기 문제가
4방향으로만 체크 가능했다면
이 문제는 대각선도 같은 덩어리로 판별한다
그것만 제외하면 완전 같은 문제
2. 문제 분석
필요변수
- 높이
int h
, 너비int w
- 최대 크기 50인 맵
int map[51][51]
. 방문 배열은 따로 사용하지 않고 map에 바로 처리했음 - 8방향을 표시할 변수
int direct[8][2]
- BFS 탐색을 위한
Queue
- BFS를 몇번 돌렸는지 = 섬의 덩어리가 몇개인지 체크할
int cnt
주의점
- w, h가 0 0 일때 반복문을 종료한다
- 8방향이므로 BFS에서 for문을 4번이 아닌 8번 돌린다.
알고리즘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. w, h 를 입력받는다
1-1. w, h가 0, 0 이면 종료한다
2. 기존의 맵을 모두 0으로 초기화한다
3. 맵의 각 셀 정보를 입력받는다.
4. 2중 For문을 통해 셀이 1인 곳을 찾아 그 지점부터 BFS를 시작한다
4-1. BFS를 통해 연결된 섬들을 맵에서 0으로 만든다
4-1-1. 큐에 시작 지점을 넣고, map 배열에서 방문처리한다 (0으로 덮어씌움)
4-1-2. 큐가 빌때까지 탐색을 계속한다
4-1-2-1. 큐의 맨 앞을 꺼낸다
4-1-2-2. 8방향으로 탐색한다
4-1-2-3. 경계를 벗어났다면 패스
4-1-2-4. 바다라면 패스
4-1-2-5. 위 조건들을 통과했다면, 방문처리하고, 큐에 삽입한다
4-2. BFS가 종료되면 섬의 개수를 + 1 해준다
3. 소스코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <queue>
#include <string.h> // for memset
#define MAX 51
using namespace std;
int w, h;
int map[MAX][MAX];
int direct[8][2] = { // ← ↑ → ↓ 순으로 시도하고, ↖ ↗ ↙ ↘ 순으로 시도한다
{0,-1},
{-1,0},
{0,1},
{1,0},
{-1,-1},
{-1,1},
{1,-1},
{1,1}
};
void BFS(int y, int x) {
queue< pair<int, int> > qu;
map[y][x] = 0;
qu.push(make_pair(y, x));
while (!qu.empty()) {
pair<int, int> now = qu.front();
qu.pop();
for (int t = 0; t < 8; t++) {
int dy = direct[t][0] + now.first;
int dx = direct[t][1] + now.second;
if (dy < 0 || dx < 0 || dy >= h || dx >= w) continue;
if (map[dy][dx] == 0) continue;
map[dy][dx] = 0;
qu.push(make_pair(dy, dx));
}
}
}
int main() {
freopen_s(new FILE*, "input.txt", "r", stdin);
while (1) {
// 0. 각 변수 초기화
memset(map, 0, sizeof(map));
cin >> w >> h;
if (w == 0 && h == 0) break;
// 1. 입력
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
cin >> map[y][x];
}
}
// 2. BFS로 섬의 개수 체크
int cnt = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if(map[y][x] == 1){
BFS(y, x);
cnt++;
}
}
}
cout << cnt << '\n';
}
return 0;
}
2024-07-12 문제를 다시 풀던 중,
BFS를 다르게 작성하여 푸는 과정에서 메모리 초과가 발생하였다
시도한 풀이는 BFS과정 외에는 다른점이 없었다
이전 풀이 방식
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void BFS(int y, int x) {
queue< pair<int, int> > qu;
map[y][x] = 0;
qu.push(make_pair(y, x));
while (!qu.empty()) {
pair<int, int> now = qu.front();
qu.pop();
for (int t = 0; t < 8; t++) {
int dy = direct[t][0] + now.first;
int dx = direct[t][1] + now.second;
if (dy < 0 || dx < 0 || dy >= h || dx >= w) continue;
if (map[dy][dx] == 0) continue;
map[dy][dx] = 0;
qu.push(make_pair(dy, dx));
}
}
}
- 방문했던 곳을 0으로 지우고, BFS를 시작한다
- 큐에 새로운 방문 가능한 구역을 넣기 전에 맵을 0으로 세팅하고 넣는다
새로 시도한 방식
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void BFS(int yy, int xx) {
queue<pair<int, int>> qu;
qu.push(make_pair(yy, xx));
while (!qu.empty()) {
pair<int, int> now = qu.front();
qu.pop();
map[now.first][now.second] = 0;
for (int t = 0; t < 8; t++) {
int dy = direct[t][0] + now.first;
int dx = direct[t][1] + now.second;
if (dy < 0 || dx < 0 || dy >= h || dx >= w) continue;
if (map[dy][dx] == 0) continue;
qu.push(make_pair(dy, dx));
}
}
}
- BFS를 시작하고 큐에서 원소를 꺼낼 때 마다 맵을 0으로 지운다
- 큐에 추가된 노드들이 중복 될 수 있다는 문제가 있다
- 예를들어 [1,1]에서 [1,2]를 큐에 넣었는데,
[1,3]에서도 [1,2]가 아직 1이라면 큐에 또 넣을 수 있는 문제가 발생할 수 있다
- 예를들어 [1,1]에서 [1,2]를 큐에 넣었는데,
- 즉 이 방법은 중복된 노드가 큐에 많이 추가될 수 있으므로, 이 방법은 안쓰는게 좋겠다
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.