[백준/C++]#7576 - 토마토
2021. 2. 13. 21:08ㆍ필요/코딩테스트(백준)
풀이
#include <cstdio>
#include <queue>
using namespace std;
int N, M;
int a[1001][1001];
int ck[1001][1001];
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
int main() {
queue<pair<int,int>> q; // pair 받는 큐 선언
scanf("%d %d", &M, &N);
for (int i=0; i<N; i++) {
for (int j=0; j<M; j++) {
scanf("%d", &a[i][j]); // 입력
ck[i][j]=-1; // ck 배열 값 초기화
if (a[i][j] == 1) { // 입력 값에 따라 어떤 값은 queue에 push
q.push(make_pair(i, j));
ck[i][j] = 0;
}
}
}
while (!q.empty()) {
int n = q.front().first;
int m = q.front().second;
q.pop();
for (int k=0; k<4; k++) {
int nx = n + dx[k];
int my = m + dy[k];
if (0<=nx && nx<N && 0<=my && my<M) {
if (a[nx][my]==0 && ck[nx][my]==-1) {
q.push(make_pair(nx, my));
ck[nx][my] = ck[n][m]+1; // 다음 ck 배열 값에 + 1
}
}
}
}
int ans = 0;
bool flag = false;
for (int i=0; i<N; i++) {
for (int j=0; j<M; j++) {
if (ans <= ck[i][j]) { // 가장 큰 값을 날짜 값으로 받음
ans = ck[i][j];
}
if (a[i][j] == 0 && ck[i][j] == -1) { // for문 탈출
ans = -1;
flag = true;
break;
}
}
if (flag == true) { // 이중 for문 탈출
break;
}
}
printf("%d", ans);
return 0;
}
개념
이중 for문을 탈출하는 법은 여러가지가 있다.
이 문제를 해결할 때는, bool 변수 flag를 사용했다.
첫 for문은 flag에 true를 대입하고 break 한 뒤, if문에서 flag가 true값일 때 break를 사용한다.
다른 방법으로는 함수를 만들어서 break 대신 return 하는 방법이 있다.
break는 가장 가까운 반복문을 나가지만, return은 무조건 함수를 탈출한다.
이 방법을 사용해보니, 코드 길이는 줄으나 시간이 더 많이 들었다.
풀이
저번 문제를 통해, bfs의 유용함을 확인했다.
이번 문제의 한 노드에서 점점 퍼져나가는 특징 역시 bfs를 사용해야한다.
다만, 여러 곳에서 동시에 퍼지는 (입력에서 1이 2개 이상) 경우가 문제이다.
이 부분은 queue의 선입선출(FIFO) 특징을 활용하면 된다.
3번째 예제를 보자.
0,0과 3,5 에서 a 배열 값이 1이다.
push_back 해서 0,0 다음 3,5가 들어간다.
그리고 0,0이 확장되어 1,0을 참조한다.
이는 0,0을 pop 하고 조건에 맞는 1,0을 push_back 하는 것과 같다.
확장될 때마다 날짜의 수가 count 되게 하는 ck[nx][my] = ck[n][m]+1; 역시 중요하다.
평소와 달리, 방문하지 않은 ck[i][j]를 -1로 설정했다.
0으로 하면, 답+1을 답으로 얻게 된다.
'필요 > 코딩테스트(백준)' 카테고리의 다른 글
[백준/C++]#1991 - 트리 순회 (2) | 2021.02.16 |
---|---|
[백준/C++]#2146 - 다리 만들기 (0) | 2021.02.15 |
[백준/C++]#2178 - 미로 탐색 (0) | 2021.02.11 |
[백준/C++]#4963 - 섬의 개수 (0) | 2021.02.10 |
[백준/C++]#2667 - 단지번호붙이기 (0) | 2021.02.09 |