개인사
[G1] 백준 1113번 수영장 만들기 C++ 구현, 시뮬레이션, 너비 우선 탐색, 플러드 필 본문
728x90

리뷰

https://www.acmicpc.net/problem/1113
낮은 수 부터 순회하며 플러드 필을 통해 해결하는 문제
전역 변수
- N : 배열의 최대 크기를 정의할 상수 변수
- dx, dy : 4방향 탐색을 위한 방향 배열
- n, m : 맵의 세로/가로 길이를 저장할 변수
- ans : 정답을 저장할 변수
- lst : 맵 정보를 저장할 2차원 배열
- v : 방문 여부를 저장할 2차원 배열
- Pos : 위치 정보를 정의할 구조체
함수
1. flood_fill
void flood_fill(int sx, int sy, int ch) {
queue<Pos> q;
q.push({ sx, sy });
queue<Pos> memo;
memo.push({ sx, sy });
v[sx][sy] = true;
int mh = 9;
bool flag = true;
while (!q.empty()) {
Pos pos = q.front(); q.pop();
int cx = pos.x, cy = pos.y;
for (int i = 0; i < 4; ++i) {
int nx = cx + dx[i], ny = cy + dy[i];
if (0 > nx || nx >= n || 0 > ny || ny >= m) {
flag = false;
continue;
}
if (lst[nx][ny] < ch) {
flag = false;
continue;
}
if (v[nx][ny]) continue;
if (lst[nx][ny] == ch) {
v[nx][ny] = true;
q.push({ nx, ny });
memo.push({ nx, ny });
}
else if (mh > lst[nx][ny]) mh = lst[nx][ny];
}
}
if (flag) {
while (!memo.empty()) {
Pos pos = memo.front(); memo.pop();
int x = pos.x, y = pos.y;
lst[x][y] = mh;
ans += mh - ch;
v[x][y] = false;
}
}
}
플러드 필을 사용해 물이 담길 수 있는 공간인지 여부를 체크하고, 물을 담는 시뮬레이션을 수행할 함수
2. print
void print() {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cout << lst[i][j];
}
cout << "\n";
}
}
디버깅용 출력 함수
문제풀이
- n, m값을 입력 받고, n*m크기의 초기 맵 정보를 입력받아 lst배열을 초기화한다.
- 1~9를 순회하며 추가로 n*m크기의 맵을 순회한다.
- 이미 방문 처리되어있거나, 현재 좌표가 h와 맞지 않은 높이인경우 continue처리한다.
- flood_fill함수에 i, j, h를 매개변수로 전달하여 호출한다. 함수 내부에서 변수 sx, sy, ch에 매개변수를 전달받는다.
- Pos타입의 큐 q, memo를 초기화 하고, 각각 sx, sy를 추가한다.
- v[sx][sy]에 방문처리 후, 변수 mh를 9로, flag를 true로 초기화한다.
- q가 빌때까지 while루프를 수행하고, 매 루프마다 요소를 한개씩 꺼내어 변수 cx, cy에 파싱한다.
- 4방향 탐색을 진행하고, 이동할 위치를 nx, ny로 저장한다.
- nx, ny가 맵 경계선 밖일 경우 flag를 false로 변경 후 continue처리한다.
- lst[nx][ny]가 ch보다 작을 경우 flag를 false로 변경 후 continue처리한다.
- v[nx][ny]가 방문한 지역이라면 continue처리한다.
- lst[nx][ny]가 ch와 같다면 v[nx][ny]에 방문처리 후 q, memo에 각각 nx, ny를 추가한다.
- lst[nx][ny]가 mh보다 작다면 mh를 lst[nx][ny]값으로 저장한다.
- while루프가 종료된 후 flag가 true인 경우 memo가 빌때까지 while루프를 수행한다. 모든 요소의 좌표를 순회하며 맵 상에서 값을 mh로 변경하고, mh-ch를 ans에 더해주고 v배열에서 방문 처리를 해제한다.
- 모든 높이별 수영장을 순회하며 최종적으로 ans에 저장된 값을 출력한다.
트러블 슈팅
없음
참고 사항
- 물은 항상 높이가 더 낮은 곳으로만 흐르고, 직육면체 위의 표면에는 물이 없다.
- 높이는 1보다 크거나 같고, 9보다 작거나 같은 자연수이다.
- 1~9높이를 순차 순회하며 플러드필 함수를 통해 아래 내용을 순차적으로 처리하면 된다.
- 맵의 밖과 연결된 그룹은 벽으로만 사용할 수 있으므로 모두 다시 방문하지 않게한다.
- 더 큰수들로 둘러쌓인 그룹은 둘러싼 값 중 가장 작은 값을 기준으로 물을 채운다.
- 이때 물을 채운 후 방문처리를 제거하여 다음 물 높이 탐색 시 해당 지역을 다시 탐색하도록한다.
- 사실상 9는 벽으로만 사용 가능하므로 탐색을 해줄 필요가 없어보인다.
- 맵 정보를 입력 받을때 최대 물 높이를 저장하고, 해당 물 높이까지만 탐색해도 가지치기가 될 것 같다.
- 가지치기를 별도 수행하지 않아도 수행시간이 0ms가 나와서 별도의 가지치기는 생략했다.
- 입력값이 공백 등으로 분리되어 있지 않기 때문에 문자로 입력 받아 정수로 파싱하는걸 추천한다.
정답 코드
#include<iostream>
#include<queue>
using namespace std;
const int N = 50;
int dx[] = { 1, -1, 0, 0 };
int dy[] = { 0, 0, 1, -1 };
int n, m, ans;
int lst[N][N];
bool v[N][N];
struct Pos {
int x, y;
};
void flood_fill(int sx, int sy, int ch) {
queue<Pos> q;
q.push({ sx, sy });
queue<Pos> memo;
memo.push({ sx, sy });
v[sx][sy] = true;
int mh = 9;
bool flag = true;
while (!q.empty()) {
Pos pos = q.front(); q.pop();
int cx = pos.x, cy = pos.y;
for (int i = 0; i < 4; ++i) {
int nx = cx + dx[i], ny = cy + dy[i];
if (0 > nx || nx >= n || 0 > ny || ny >= m) {
flag = false;
continue;
}
if (lst[nx][ny] < ch) {
flag = false;
continue;
}
if (v[nx][ny]) continue;
if (lst[nx][ny] == ch) {
v[nx][ny] = true;
q.push({ nx, ny });
memo.push({ nx, ny });
}
else if (mh > lst[nx][ny]) mh = lst[nx][ny];
}
}
if (flag) {
while (!memo.empty()) {
Pos pos = memo.front(); memo.pop();
int x = pos.x, y = pos.y;
lst[x][y] = mh;
ans += mh - ch;
v[x][y] = false;
}
}
}
void print() {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cout << lst[i][j];
}
cout << "\n";
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
char c; cin >> c;
lst[i][j] = c - '0';
}
}
for (int h = 1; h <= 9; ++h) {
//cout << "\n";
//print();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (v[i][j]) continue;
if (lst[i][j] != h) continue;
flood_fill(i, j, h);
}
}
}
cout << ans;
}728x90
'알고리즘 공부 > C++' 카테고리의 다른 글
| [G3] 백준 2457번 공주님의 정원 C++ 그리디 알고리즘, 우선순위 큐 (0) | 2025.10.29 |
|---|---|
| [G2] 백준 1135번 뉴스 전하기 C++ 트리, 깊이 우선 탐색, 그리디 알고리즘, 정렬 (0) | 2025.10.29 |
| [G5] 백준 1011번 Fly me to the Alpha Centauri C++ 수학, 투 포인터 (0) | 2025.10.29 |
| [G5] 백준 3967번 매직 스타 C++ 구현, 백트래킹 (0) | 2025.10.29 |
| [S2] 백준 6603번 로또 C++ 백트래킹 (0) | 2025.10.29 |
