https://www.acmicpc.net/problem/7569
7569번: 토마토
첫 줄에는 상자의 크기를 나타내는 두 정수 M,N과 쌓아올려지는 상자의 수를 나타내는 H가 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M ≤ 100, 2 ≤ N ≤ 100,
www.acmicpc.net
상자의 각 칸을 노드로, 칸 사이의 인접한 관계를 에지로 보면 이 문제는 3차원 그래프를 탐색하는 문제로 볼 수 있다. bfs를 아직 익지 않은 토마토의 개수, 즉 값이 0인 노드의 개수를 추적하면서, 그래프를 모두 탐색했을 때 값이 0인 노드를 모두 탐색했다면 bfs의 단계의 수를, 그렇지 않다면 -1을 출력한다. 이 때 이 단계의 수를 출력하는 문제이므로 dfs는 사용할 수 없다.
#include <iostream>
#include <queue>
using namespace std;
#define MAX_N 100
#define FOR(i, a, b) for(i = a; i < b; i++)
// 토마토가 담긴 칸의 좌표
class coord {
public:
int h, n, m;
coord() { h = n = m = 0; }
coord(int h, int n, int m) { this->h = h; this->n = n; this->m = m; }
// 좌표 간의 덧셈
coord operator+(coord c) {
return { this->h + c.h, this->n + c.n, this->m + c.m };
}
};
// M, N, H: 상자의 크기, cnt: 설익은 토마토의 수
int M, N, H, cnt = 0;
// box[h][n][m]: 상자의 각 칸에 든 물건의 종류.
// 0 -> 설익은 토마토, 1 -> 익은 토마토, -1 -> 빈칸
short box[MAX_N][MAX_N][MAX_N];
// q 안의 좌표를 더할 때 사용할 변위
coord add[6]= {{0, 0, -1}, {0, 0, 1}, {0, -1, 0}, {0, 1, 0}, {-1, 0, 0}, {1, 0, 0}};
// bfs에 사용할 큐
queue<coord> q;
// c가 상자 안의 좌표인지 여부를 반환
bool valid(coord c) {
return c.h >= 0 && c.h < H && c.n >= 0 && c.n < N && c.m >= 0 && c.m < M;
}
int bfs() {
// len: time 시간에 다 익은 토마토의 수, time: 토마토가 전부 익는데 걸리는 시간
int len = q.size(), time = 0;
// c: queue의 front, c_: c에 인접한 좌표
coord c, c_;
// 인접 칸에 영향을 미칠 수 있는 토마토가 존재한다면
while(!q.empty()) {
// q에서 좌표를 하나 가져온 뒤
c = q.front();
q.pop();
// 인접 칸의 토마토를 익힐 수 있다면 익힌 칸을 q에 push
for (auto a : add) {
// c에 인접한 칸 c_에 대해
c_ = c + a;
// c_가 상자 밖의 좌표거나 안에 든 게 설익은 토마토가 아닐 경우 continue
if (!valid(c_) || box[c_.h][c_.n][c_.m]) continue;
// 설익은 토마토를 익은 토마토로 바꾸고 설익은 토마토의 수를 1 줄인다
cnt -= (box[c_.h][c_.n][c_.m] = 1);
// 다 익은 토마토의 좌표를 q에 push
q.push(c_);
}
// time 시간에 다 익은 토마토를 모두 탐색했다면 time과 len을 갱신
if (!--len) time += (bool)(len = q.size());
}
// 토마토가 다 익었다면 다 익는데 걸리는 시간을, 아니라면 -1을 반환
return !cnt ? time : -1;
}
int main() {
// 입출력 속도 향상
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
// for문에서 사용할 변수
int h, n, m;
// 상자의 크기와 각 칸의 상태를 입력받은 뒤
cin >> M >> N >> H;
FOR(h, 0, H) FOR(n, 0, N) FOR(m, 0, M) {
cin >> box[h][n][m];
// 익은 토마토가 있는 칸을 q에 push
if (box[h][n][m] == 1) q.push({h, n, m});
// 설익은 토마토의 수를 저장
cnt += !box[h][n][m];
}
// 입력받은 그래프를 탐색한 결과를 출력
cout << bfs() << '\n';
return 0;
}
'알고리즘 > 문제 풀이' 카테고리의 다른 글
7579번: 앱 (0) | 2021.12.24 |
---|---|
7576번: 토마토 (0) | 2021.12.24 |
7568번: 덩치 (0) | 2021.12.24 |
6603번: 로또 (0) | 2021.12.24 |
6064번: 카잉 달력 (0) | 2021.12.24 |