본문 바로가기

알고리즘/백준 문제풀기

BOJ 백준 7569 토마토

https://www.acmicpc.net/problem/7569


<토마토>


 이 문제는 한 토마토가 익은 상태라면, 다음 날에는 그 토마토의 앞, 뒤, 왼쪽, 오른쪽, 위, 아래의 토마토가 익게 되는데,


이 때 상자에 있는 모든 토마토가 익는 데에 최소 몇 일이 걸리는 지 계산해주어 출력해주는 문제이다.


모든 토마토를 익게 할 수 없을 시에는 -1을 출력해주고, 처음부터 모든 토마토가 익어있는 경우엔 0을 출력해주면 된다.



하나 하나가 자신의 전후좌우를 전염시켜나가는 문제들과 유사한데, 조금 다른 점은 한 층의 배열이 아닌


여러 층으로 이루어져 상, 하까지 전염시켜주어야 하는 것이다.



3차원 배열을 자주 사용해보진 않았지만, 예를들어 2 x 3 배열이 2개 있다는 것은 2 x 2 x 3으로 생각하면 되므로


int arr[2][3] 을 int arr[2][2][3]으로만 선언해주면 된다고 생각하고 문제를 풀었다.



문제는 다른 높이가 없는 토마토 문제처럼 BFS 알고리즘을 이용하여 풀었다.


처음 익은 토마토(1)와 익지 않은 토마토(0), 빈 상자(-1)를 입력 받게 되는데, 익은 토마토를 입력 받았을 때


queue에 넣어주는 형태로 했다.


물론 queue를 하나로 만들어 queue<pair<int, pair<int, int> > > q 형태로 선언되도 되겠지만,


좀 편하게 코딩하고 싶어서 높이 큐와 좌표 큐를 따로 두어 넣었다.



#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <queue> #define SIZE 101 using namespace std; enum TOMATO_RIPE { N_RIPE, RIPE }; int n, m, h; int tomato[SIZE][SIZE][SIZE]; bool IsRipe[SIZE][SIZE][SIZE]; int total_tomato = 0; // 익지 않은 토마토 개수 int harr[6] = { 0, 0, 0, 0, 1, -1 }; int xarr[6] = { 1, -1, 0, 0, 0, 0 }; int yarr[6] = { 0, 0, 1, -1, 0, 0 }; queue<int> qH; // 높이 큐 queue<pair<int ,int> > qNM; // 좌표 큐 bool InMap(int _h, int _n, int _m) { return (0 <= _h && _h < h && 0 <= _n && _n < n && 0 <= _m && _m < m); } int solution() { int iDay = 0; int iTomato = 0; bool flag = false; while (!qH.empty()) { int qsize = qH.size(); for (int i = 0; i < qsize; i++) { int cur_h = qH.front(); int cur_x = qNM.front().first; int cur_y = qNM.front().second; qH.pop(); qNM.pop(); for (int j = 0; j < 6; j++) { int next_h = cur_h + harr[j]; int next_x = cur_x + xarr[j]; int next_y = cur_y + yarr[j]; // 토마토 상자 밖인 경우 if (!InMap(next_h, next_x, next_y)) continue; // 익은 토마토인 경우 if (IsRipe[next_h][next_x][next_y]) continue; // 토마토가 아닌, 빈 상자인 경우 if (tomato[next_h][next_x][next_y] == -1) continue; // 익었다는 표시 IsRipe[next_h][next_x][next_y] = 1; // 큐에 넣어주기 qH.push(next_h); qNM.push({ next_x, next_y }); // 익은 토마토 개수 증가 iTomato++; // 날짜 증가 플래그 flag = true; } } // 토마토가 익은 경우에만 날짜 증가 if (flag) { iDay++; flag = false; } } // 전부 익었다면 if(iTomato == total_tomato) return iDay; // 같지 않다면 일부가 익지 못했으므로 -1 리턴 else return -1; } int main() { memset(IsRipe, false, sizeof(IsRipe)); // m : 가로 n : 세로 scanf("%d %d %d", &m, &n, &h); for (int i = 0; i < h; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < m; k++) { scanf("%d", &tomato[i][j][k]); if (tomato[i][j][k] == RIPE) { IsRipe[i][j][k] = true; qH.push(i); qNM.push({ j, k }); } else if (tomato[i][j][k] == N_RIPE) total_tomato++; } } } // 익지 않은 토마토 개수가 없는 경우 if (total_tomato == 0) printf("0\n"); // 익은 토마토가 한 개도 없는 경우 else if (qH.size() == 0) printf("-1\n"); else printf("%d\n", solution()); return 0; }



ps. 계속 틀려 반례를 찾지 못해 백준 질문 게시판에 올렸는데, 다른 고수님이 내 코드에서 가로, 세로, 높이 순으로 입력이 들어오는 것을


세로, 가로, 높이로 받아오고 있다는 걸 발견하고 알려주셨다. 내가 짠 코드를 다른 사람이 더 잘 분석하다니.. 더 꼼꼼하고 치밀하게 봐야겠다.


'알고리즘 > 백준 문제풀기' 카테고리의 다른 글

BOJ 백준 1753 최단경로  (0) 2018.12.11
BOJ 백준 2644 촌수계산  (0) 2018.12.10
BOJ 백준 1068 트리  (0) 2018.12.08
BOJ 백준 9461 파도반 수열  (0) 2018.11.21
BOJ 백준 12100 2048 (Easy)  (0) 2018.11.21