[BOJ] 7576 토마토
1. 문제링크
https://www.acmicpc.net/problem/7576
2.해설
이 문제는 전형적인 BFS문제이다.
문제 풀이 순서는 이러하다.
1. 시작점을 찾는다.
2. BFS로 가능한 만큼 토마토를 다 익힌다.
3. 다 익었는지 확인 하고 다 익었다면 구한 cnt를 ans에 대입하고 출력한다.
시간복잡도는 BFS의 시간복잡도인 O(VE) 이고 이 문제에서는 O(n^2) 이다.
3. 소스코드
#include<iostream> #include<cstring> #include<queue> using namespace std; #define MAXNUM 1010 struct point{ int x, y; }; bool isRipe(int n, int m, int tomato[][MAXNUM]); int main(){ int n, m, ans=-1, cnt=0; int tomato[MAXNUM][MAXNUM]={0}; int dx[4] = {1, 0, -1, 0}; int dy[4] = {0, 1, 0, -1}; queue<point> q; memset(tomato, -1, sizeof(tomato)); scanf("%d %d", &m, &n); for (int i=1; i<=n; i++) { for (int j=1; j<=m; j++) { scanf("%d", &tomato[i][j]); //시작 지점 push if (tomato[i][j] == 1) q.push({j, i}); } } while (!q.empty()) { int size = (int)q.size(); cnt++; for (int l=0; l<size; l++) { point cur = q.front(); q.pop(); //상하좌우 4방향 확인하고... for (int i=0; i<4; i++) { point next = {cur.x + dx[i], cur.y + dy[i]}; //안 익은 토마토라면 큐에 push한다. if (tomato[next.y][next.x] == 0) { tomato[next.y][next.x] = 1; q.push(next); } } } } if (isRipe(n, m, tomato)) { ans = cnt-1; } printf("%d\n", ans); return 0; } //다 익었는지 확인 bool isRipe(int n, int m, int tomato[][MAXNUM]){ for (int i=1; i<=n; i++) { for (int j=1; j<=m; j++) { if (tomato[i][j] == 0) { return false; } } } return true; }
4. 추가 언급
BFS문제들은 조금만 실수해도 메모리가 터진다거나, 시간이 터지는 경우가 굉장히 많다. 이 토마토 문제도 언제 익었다라고 확인 해주는 가에 따라서 메모리가 터질 수도 안 터질 수도 있다. 우리는 queue에 넣을 때 익었다 라고 확인을 해준다. 그렇다면 while문을 이렇게 바꾸면 어떻게 될까. 한번 생각해보자.
while (!q.empty()) { int size = (int)q.size(); cnt++; for (int l=0; l<size; l++) { point cur = q.front(); q.pop(); tomato[cur.y][cur.x] = 1; //상하좌우 4방향 확인하고... for (int i=0; i<4; i++) { point next = {cur.x + dx[i], cur.y + dy[i]}; //안 익은 토마토라면 큐에 push한다. if (tomato[next.y][next.x] == 0) { //tomato[next.y][next.x] = 1; q.push(next); } } } }
이렇게 된다면 우리는 queue에서 꺼낼 때 확인을 한다. 이렇게 된다면 메모리 초과가 될 것이다. 왜그럴까?
왜냐하면 같은 곳이 중복해서 들어갈 수 있기 때문이다. 내가 만약 (2, 2)를 가고 싶다고 하는데 큐에 (1, 2), (2, 1)이 있다고 해보자. 그러면 (2, 2) 큐에 있는 (1, 2), (2, 1)에 대해서 둘 다 (2, 2)가 큐에 들어가게 된다. 이렇게 100번만 지나면 2^100개가 넘어가는 중복된 값이 큐에 들어가게 된다. 메모리가 터지는 것은 당연할 것이다.
우리는 이렇게 BFS를 할 때는 확인을 어떻게, 언제 해줘야 중복 확인을 안 하는지 언제나 생각을 하면서 코드를 짜야할 것이다.
'프로그래밍 > 문제풀이(boj)' 카테고리의 다른 글
[BOJ] 1525 퍼즐 (0) | 2018.09.06 |
---|---|
[BOJ] 2225 합분해 (0) | 2018.09.06 |
[BOJ] 10814 나이순정렬, Stable의 뜻 (0) | 2018.09.04 |
[BOJ] 10828 스택, 전방선언 (0) | 2018.09.01 |
[BOJ] 9012 괄호 (0) | 2018.09.01 |