고코딩

[백준 7576번] 토마토 본문

코딩테스트

[백준 7576번] 토마토

고코딩 2021. 1. 18. 11:36

문제

철수의 토마토 농장에서는 토마토를 보관하는 큰 창고를 가지고 있다. 토마토는 아래의 그림과 같이 격자 모양 상자의 칸에 하나씩 넣어서 창고에 보관한다.

창고에 보관되는 토마토들 중에는 잘 익은 것도 있지만, 아직 익지 않은 토마토들도 있을 수 있다. 보관 후 하루가 지나면, 익은 토마토들의 인접한 곳에 있는 익지 않은 토마토들은 익은 토마토의 영향을 받아 익게 된다. 하나의 토마토의 인접한 곳은 왼쪽, 오른쪽, 앞, 뒤 네 방향에 있는 토마토를 의미한다. 대각선 방향에 있는 토마토들에게는 영향을 주지 못하며, 토마토가 혼자 저절로 익는 경우는 없다고 가정한다. 철수는 창고에 보관된 토마토들이 며칠이 지나면 다 익게 되는지, 그 최소 일수를 알고 싶어 한다.

토마토를 창고에 보관하는 격자모양의 상자들의 크기와 익은 토마토들과 익지 않은 토마토들의 정보가 주어졌을 때, 며칠이 지나면 토마토들이 모두 익는지, 그 최소 일수를 구하는 프로그램을 작성하라. 단, 상자의 일부 칸에는 토마토가 들어있지 않을 수도 있다.

입력

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토들의 정보가 주어진다. 즉, 둘째 줄부터 N개의 줄에는 상자에 담긴 토마토의 정보가 주어진다. 하나의 줄에는 상자 가로줄에 들어있는 토마토의 상태가 M개의 정수로 주어진다. 정수 1은 익은 토마토, 정수 0은 익지 않은 토마토, 정수 -1은 토마토가 들어있지 않은 칸을 나타낸다.

토마토가 하나 이상 있는 경우만 입력으로 주어진다.

출력

여러분은 토마토가 모두 익을 때까지의 최소 날짜를 출력해야 한다. 만약, 저장될 때부터 모든 토마토가 익어있는 상태이면 0을 출력해야 하고, 토마토가 모두 익지는 못하는 상황이면 -1을 출력해야 한다.


정답

이 문제를 풀면서 정말 다양한 문제를 풀어봐야하는구나 라는 것을 뼈저리게 느꼈다. 풀면서 계속해서 내 머릿속에 없었던 예외상황이 나오고 그 테스트케이스를 만족하면서 푸는게 어려웠다.

제일 어려웠던것은 토마토가 서로 다른곳에서 익기 때문에 중간에서 익은 토마토끼리 만날수 있다는 점이다. 이 부분은 맨 처음 익은 토마토들을 다 큐에 담아서 풀어야 했다. 내 생각은 큐에 익은 토마토들을 담을 생각자체를 못했다. 왜냐면 나는 미로탐색같이 한 점에서만 깊이 탐색 하는 문제만 풀었기 때문이다.

  1. 토마토가 익은 점들을 큐에 넣어준다.( 익음이 동시 다발적으로 일어나기 때문에 큐를 사용한 BFS를 사용)
  2. 익은 토마토 상하좌우를 탐색하며 익지 않은 토마토가 있으면 그 위치를 큐에 넣어준다. (그 위치으 값은 최대 일수를 계산하기 위해 전 위치 +1을 해준다.)
  3. 큐가 빌때까지 계속해준다.
  4. 전체 토마토들을 탐색하여 익지않은 토마토가 하나라도 있으면 -1을 출력한다.
  5. 그 외는 최대 일수를 출력한다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;

public class Main {
    static class Graph{
        int n,m;
        int[][] box;
        int[] di = {0,0,1,-1};
        int[] dj = {1,-1,0,0};
        LinkedList<Integer> highday = new LinkedList<Integer>();
        public Graph(int n, int m) {
            box = new int[n][m];
            this.n = n;
            this.m = m;
            highday.add(0);//다 익은 토마토만 있을 경우도 있기 때문에 0일 추가해줘야함
        }
        //박스 정보 생성
        public void addBox(String[] boxinfo, int n) {

            for(int i=0;i<boxinfo.length;i++) {
                box[n][i] = Integer.parseInt(boxinfo[i]);
            }
        }

        //토마토 익히는거 시작
        public void dotomato() {

            int day = BFS();
            highday.add(day);

            //전체 돌면서 안 익은 토마토 있으면 -1호출 그리고 끝 없으면 최대값 출력
            for(int i=0 ; i<n ; i++) {
                for(int j=0 ; j<m;j++) {
                    if(box[i][j]==0) {
                        System.out.println("-1");
                        return;
                    }
                }
            }
            Collections.sort(highday);

            System.out.println(highday.get(highday.size()-1));


        }

        //너비 우선 탐색
        //
        public int BFS() {
            boolean check = false;//하루 이상 지났는지 아닌지 체크요
            //너비탐색용 큐 생성
            Queue<Node> que = new LinkedList<Node>();
            //익은 토마토들 큐에 삽입
            for(int x = 0; x<n ; x++) {
                for(int y = 0 ; y<m ; y++) {
                    if(box[x][y]==1)
                        que.add(new Node(x,y));
                }
            }

            int highestday = 0;    //최대날 카운트
            //큐가 빌때까지 반복
            while(!que.isEmpty()) {
                Node tomato = que.poll();
                for(int d=0;d<4;d++) {
                    int ni = tomato.i + di[d];
                    int nj = tomato.j + dj[d];
                    //주변 배열 값이 박승안에 값이면서 0(안 익은 토마토일때)일때
                    if(ni>=0 && nj>=0 && ni<n && nj<m && box[ni][nj] == 0) {
                        check = true;
                        box[ni][nj] = box[tomato.i][tomato.j]+1;
                        que.add(new Node(ni,nj));
                        highestday = highestday < box[ni][nj] ? box[ni][nj] : highestday;
                    }
                }
            }
            if(check == false) {
                return 0;
            }
            return highestday-1;    //처음 토마토가 익는 날이 2일째 부터로 계산해서 1 빼줘야함
        }
    }
    public static class Node {
        int i,j;
        public Node(int i,int j) {
            this.i = i;
            this.j = j;
        }
    }
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringBuffer sf = new StringBuffer();

        String[] MN = br.readLine().split(" ");

        int M = Integer.parseInt(MN[0]);    // 가로수
        int N = Integer.parseInt(MN[1]);    // 세로수 배열[N][M]

        Graph g = new Graph(N,M);

        for(int i=0;i<N;i++) {
            String [] box = br.readLine().split(" ");
            //박스 생성
            g.addBox(box, i);
        }

        //토마토 탐색
        //배열 돌면서 1일때 토마토 익힘, 최대 값 저장
        //BFS다 돌았을때 박스안에 0이 있으면 -1 출력
        //0 없으면 최대값 출력
        g.dotomato();


        br.close();
        bw.flush();
        bw.close();
    }
}

이 문제는 다른 블로그의 푼 문제를 참고해서 풀었다. 다시 말해 내 생각대로 푼 문제가 아니라는 것이다. 그리고 제일 어려웠던것은 내가 쓴 코드를 다른사람이 보고 이해하기 쉽게 코딩해야하는점이 제일 어려웠다. 아무래도 이런 부분들을 키워나가야 겠다.
밑에는 내가 참고한 블로그이다.

https://zoonvivor.tistory.com/131

 

[BOJ] 백준 7576 - 토마토 (자바)

BFS,,... 오랜만에 BFS 문제 풀려고 했었는데 생각이 않났다. 그래서 시간 두고 다시 풀어봄. 아주 단순히 이전 값에 +1 해주면 되는 거였다. 풀이 1. 토마토가 익은 점들을 큐에 넣어준다. (동시 다발

zoonvivor.tistory.com

 

'코딩테스트' 카테고리의 다른 글

[백준 1697번] 숨바꼭질  (0) 2021.01.19
[백준 2606번] 바이러스  (0) 2021.01.18
[백준 2667번] 단지번호붙이기  (0) 2021.01.14
[백준 2178번] 미로 탐색  (0) 2021.01.14
[백준 1260번] DFS와 BFS  (0) 2021.01.13