문제 출처: https://www.acmicpc.net/problem/7576
문제
창고에 보관되는 토마토들 중에는 잘 익은 것도 있지만, 아직 익지 않은 토마토들도 있을 수 있다. 보관 후 하루가 지나면, 익은 토마토들의 인접한 곳에 있는 익지 않은 토마토들은 익은 토마토의 영향을 받아 익게 된다. 하나의 토마토의 인접한 곳은 왼쪽, 오른쪽, 앞, 뒤 네 방향에 있는 토마토를 의미한다. 대각선 방향에 있는 토마토들에게는 영향을 주지 못하며, 토마토가 혼자 저절로 익는 경우는 없다고 가정한다. 철수는 창고에 보관된 토마토들이 며칠이 지나면 다 익게 되는지, 그 최소 일수를 알고 싶어 한다.
토마토를 창고에 보관하는 격자모양의 상자들의 크기와 익은 토마토들과 익지 않은 토마토들의 정보가 주어졌을 때, 며칠이 지나면 토마토들이 모두 익는지, 그 최소 일수를 구하는 프로그램을 작성하라. 단, 상자의 일부 칸에는 토마토가 들어있지 않을 수도 있다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
private static int[][] directions = {
{ -1, 0 }, // 상
{ 1, 0 }, // 하
{ 0, -1 }, // 좌
{ 0, 1 }, // 우
};
private static Queue<int[]> tomatoList = new ArrayDeque<>(); // 인덱스 0: 행, 인덱스 1: 열
private static int[][] tomatoes; // 토마토 정보를 저장하기 위한 배열
private static int countOne, countZero, countMinusOne; // 1, 0, -1 각각 카운트
private static int result; // 정답용
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer tokenizer = new StringTokenizer(reader.readLine());
int M = Integer.parseInt(tokenizer.nextToken()); // 상자 가로 길이
int N = Integer.parseInt(tokenizer.nextToken()); // 상자 세로 길이
tomatoes = new int[N][M];
for (int i = 0; i < N; i++) {
tokenizer = new StringTokenizer(reader.readLine());
for (int j = 0; j < M; j++) {
tomatoes[i][j] = Integer.parseInt(tokenizer.nextToken());
if (tomatoes[i][j] == 1) {
tomatoList.offer(new int[] { i, j }); // 익은 토마토 위치 삽입
countOne++;
}
else if (tomatoes[i][j] == 0) countZero++;
else countMinusOne++;
}
}
// 모든 토마토가 다 익었거나, 익은 토마토와 빈 상자로만 구성된 경우 바로 리턴
if (countOne == N * M || countOne + countMinusOne == N * M) {
System.out.println(0);
return;
}
while (!tomatoList.isEmpty()) {
int size = tomatoList.size();
boolean flag = false;
while (size-- > 0) {
if (bfs(tomatoList.poll(), N, M)) flag = true;
}
if (flag) result++;
}
// 모두 익지 못하는 상황
if (countOne + countMinusOne != N * M) {
System.out.println(-1);
return;
}
System.out.println(result);
}
private static boolean bfs(int[] code, int N, int M) {
int y = code[0];
int x = code[1];
boolean flag = false;
for (int i = 0; i < 4; i++) {
int dy = y + directions[i][0];
int dx = x + directions[i][1];
// 유효한 좌표값이고
if (dy >= 0 && dy < N && dx >= 0 && dx < M) {
// 익지 않은 토마토일 경우
if (tomatoes[dy][dx] == 0) {
tomatoes[dy][dx] = 1; // 토마토가 익음
countOne++;
flag = true;
tomatoList.add(new int[] { dy, dx });
}
}
}
return flag;
}
}