1. 문제 정보
- 문제 번호: 1012번
- 문제 이름: 유기농 배추
- 문제 요약: NXM 격자에 배추가 심어져 있다. 상하좌우로 인접한 배추들은 하나의 지렁이로 보호할 수 있다. 총 몇 마리의 지렁이가 필요한지 구하라.
2. 접근 방법 (알고리즘)
BFS(너비 우선 탐색)를 활용한 군집 탐색
이 문제는 그래프에서 연결 요소(Connected Components)의 개수를 세는 문제입니다.
- 전수 조사: 격자의 (0, 0)부터 (N-1, M-1)까지 차례대로 방문합니다.
- 새로운 덩어리 발견: 만약 해당 칸에 배추가 있고(1), 아직 방문하지 않았다면(!visited) 새로운 지렁이가 필요한 시점입니다.
- 영역 확장: 그 칸을 시작점으로 BFS를 돌려 인접한 모든 배추를 방문 처리(visited = true)합니다. 이 과정이 끝나면 지렁이 한 마리가 커버할 수 있는 모든 영역이 표시됩니다.
- 카운트: BFS가 한 번 끝날 때마다 지렁이 수를 +1 해줍니다.
3. 핵심 포인트: "초기화의 중요성" ⚠️
이 문제는 여러 개의 테스트 케이스(T)가 주어집니다. 여기서 가장 많이 하는 실수가 이전 테스트 케이스의 데이터가 배열에 남아있는 것입니다.
<cstring>과 memset
사용자가 해결한 핵심 열쇠죠! 각 테스트 케이스가 시작될 때마다 ground 배열과 visited 배열을 깨끗하게 비워줘야 합니다.
- memset(target, value, size): 메모리 블록을 특정 값으로 한꺼번에 채워주는 함수입니다.
- 0이나 false로 초기화할 때 매우 빠르고 효율적입니다.
4. 코드 구현
#include <iostream>
#include <queue>
#include <cstring> // memset을 사용하기 위한 라이브러리
using namespace std;
int M, N, K;
int ground[50][50];
bool visited[50][50];
int dx[4] = {1, -1, 0, 0}; // 상하좌우 탐색을 위한 방향 벡터
int dy[4] = {0, 0, 1, -1};
void bfs(int x, int y) {
queue<pair<int,int>> q;
q.push({x,y});
visited[x][y] = true;
while(!q.empty()) {
int cx = q.front().first;
int cy = q.front().second;
q.pop();
for(int i=0; i<4; i++) {
int nx = cx + dx[i];
int ny = cy + dy[i];
// 격자 범위 내에 있고, 배추가 있으며, 방문하지 않은 경우
if(nx >= 0 && nx < N && ny >= 0 && ny < M) {
if(ground[nx][ny] == 1 && !visited[nx][ny]) {
visited[nx][ny] = true;
q.push({nx,ny});
}
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while(T--) {
cin >> M >> N >> K;
// 1. 매 테스트 케이스마다 배열 초기화 (가장 중요!)
memset(ground, 0, sizeof(ground));
memset(visited, false, sizeof(visited));
for(int i=0; i<K; i++) {
int x, y;
cin >> x >> y;
ground[y][x] = 1; // y를 행(세로), x를 열(가로)로 매칭
}
int wormCount = 0;
// 2. 격자 전체를 순회하며 BFS 시작점 찾기
for(int i=0; i<N; i++) {
for(int j=0; j<M; j++) {
if(ground[i][j] == 1 && !visited[i][j]) {
bfs(i,j);
wormCount++; // BFS가 호출될 때마다 지렁이 한 마리 추가
}
}
}
cout << wormCount << "\n";
}
return 0;
}
5. 배운 점 & 회고 (TIL) ✍️
① 다중 테스트 케이스는 "무조건 초기화"
"이게 왜 안 되지?" 싶을 땐 초기화 문제입니다. memset 사용법을 익힐 수 있었습니다.
② 좌표 평면과 배열 인덱스의 혼동
문제에서는 가로(M), 세로($N$)로 주어지는데, 우리는 보통 배열을 arr[row][col] 순서로 씁니다. 즉, 배열의 행이 세로(N), 열이 가로(M)**가 됩니다. 입력받을 때 ground[y][x]로 넣어주는 디테일이 아주 중요했습니다.
③ BFS의 범용성
'바이러스' 문제처럼 인접 리스트로 푸는 그래프나, 이번 문제처럼 격자(Grid) 위에서 푸는 문제나 "방문 처리로 중복을 막는다"는 핵심 원리는 똑같다는 걸 체감했습니다.
'알고리즘 문제풀이 > C++' 카테고리의 다른 글
| [백준/C++] 2630번: 색종이 만들기 - 분할 정복과 재귀의 정석 (0) | 2026.03.17 |
|---|---|
| [백준/C++] 1927번: 최소 힙 - priority_queue의 내부 구조 파헤치기 (0) | 2026.03.10 |
| [백준/C++] 9095번: 1, 2, 3 더하기 - DP의 정석을 맛보다 (0) | 2026.03.02 |
| [백준/C++] 2839번: 설탕 배달 - 브루트 포스에서 DP로 나아가기 (0) | 2026.02.28 |
| [백준/C++] 11723번: 집합 - 비트마스킹을 활용한 최적화 (0) | 2026.02.22 |