Algorithm

백준 7576: 토마토

10Biliion 2025. 3. 20. 18:42
반응형

 

N × M 크기의 상자에 익은 토마토(1)와 익지 않은 토마토(0), 그리고 토마토가 들어있지 않은 칸(-1)이 있다. 익은 토마토는 하루가 지나면 상하좌우로 인접한 익지 않은 토마토를 익게 만든다. 모든 토마토가 익는 데 걸리는 최소 일수를 구하는 문제이다. 만약 모든 토마토를 익힐 수 없다면 -1을 출력해야 한다.

 

이 문제는 BFS(너비 우선 탐색) 을 활용하여 해결할 수 있다. BFS를 사용하면 여러 지점에서 동시에 탐색을 진행할 수 있으며, 최단 거리 계산에 유리하다.


2. BFS 알고리즘을 활용한 해결 방법

BFS 수행

  • Queue를 사용하여 익은 토마토의 위치에서 시작하여 상하좌우로 탐색을 진행한다.
  • 각 날짜마다 익는 토마토를 Queue에 추가하고, 하루가 지날 때마다 days 값을 증가시킨다.
  • queue.size() 만큼만 반복하여 한 번의 BFS 반복이 하루를 의미하도록 한다.

결과 계산

  • BFS 탐색이 끝난 후 map에 익지 않은 토마토(0)가 남아있으면 -1을 출력한다.
  • 모든 토마토가 익었다면 days - 1을 출력한다. (days는 BFS의 반복 횟수이므로, 첫날을 제외한 실제 걸린 일수는 days - 1이다.)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};
    static int[][] map;
    static int days;

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int y = Integer.parseInt(st.nextToken());
        int x = Integer.parseInt(st.nextToken());

        map = new int[x][y];
        Queue<int[]> queue = new LinkedList<>();

        for (int i = 0; i < x; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < y; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
                if (map[i][j] == 1) queue.offer(new int[] {i, j});
            }
        }

        bfs(queue);
        
        for (int i = 0; i < x; i++) {
            for (int j = 0; j < y; j++) {
                if (map[i][j] == 0) {
                    System.out.println(-1);
                    return;
                }
            }
        }

        System.out.println(days - 1);

    }

    static void bfs(Queue<int[]> queue) {
        days = 0;

        while (!queue.isEmpty()) {

            int size = queue.size();

            for (int i = 0; i < size; i++) {
                int[] arr = queue.poll();
                int nowX = arr[0];
                int nowY = arr[1];

                for (int k = 0; k < 4; k++) {
                    int nextX = nowX + dx[k];
                    int nextY = nowY + dy[k];

                    if (nextX >= 0 && nextY >= 0 && nextX < map.length && nextY < map[0].length && map[nextX][nextY] == 0) {
                        queue.offer(new int[] {nextX, nextY});
                        map[nextX][nextY] = 1;
                    }
                }
            }

            days++;

        }

    }


}

1) BFS 탐색을 위한 방향 배열

  • BFS 탐색 시, 상하좌우 방향으로 이동하기 위한 배열이다.

2) 초기 토마토 위치를 Queue에 저장

  • 익은 토마토(1)를 BFS 탐색의 시작점으로 Queue에 저장한다.

3) bfs() 함수에서 BFS 탐색 진행

  • queue.size() 만큼 반복하여 한 번의 루프가 하루를 의미하도록 구현한다.
  • poll()을 이용해 현재 익은 토마토를 꺼내고, 상하좌우의 익지 않은 토마토를 익게 한다.
  • 방문한 칸을 1로 변경하여 중복 방문을 방지한다.
  • 하루가 끝날 때마다 days++ 증가시킨다.

4) 결과 계산

  • BFS 수행 후에도 익지 않은 토마토(0)가 남아있다면 -1을 출력한다.
  • 모든 토마토가 익었다면 days - 1을 출력한다.
 

5. 시간 복잡도 분석

  • BFS의 시간 복잡도는 O(NM) (N: 행 개수, M: 열 개수)
  • Queue를 사용하여 모든 노드를 한 번씩 탐색하므로 효율적인 해결 방법이다.
 
반응형