[백준 | node.js] 7576번: 토마토 BFS 풀이

2025. 1. 30. 02:53·Coding Test/BackJoon

백준 7576번 토마토 문제 링크

https://www.acmicpc.net/problem/7576 


문제 정리

- 토마토가 모두 익을 때까지의 최소 날짜를 구하는 문제

- 1: 익은 토마토, 0: 익지 않은 토마토, -1: 토마토가 들어있지 않은 칸

- 익은 토마토는 상하좌우 방향으로 인접한 토마토를 하루에 하나씩 익게 한다.

문제 출력

- 저장될 때부터 모든 토마토가 익어있는 상태라면 0

- 토마토가 모두 익지는 못하는 상황이면 -1

- 그 외의 경우 걸리는 최소 일수

문제 접근

0. 문제 유형 파악하기

익은 토마토가 인접한 토마토를 하나씩 익게하고 전체를 모두 익게 하는데 걸리는 최소 일수를 요구했으므로 BFS 로 풀이한다.

시작점이 여러 개(=익은 토마토들의 위치)라는 점이 특징이다.

 

1. 초기 설정

- 상하좌우 방향 벡터를 설정한다.

- visited 배열 : 익은 날짜를 기록하는 곳

- queue : 익은 토마토의 위치를 저장하는 곳

 

2. 토마토 상태 파악하기

- 익은 토마토는 익은 토마토의 위치를 queue에 저장한다. (시작점이 여러개)

- 빈 공간은 visitied에 -1로 표시한다.

 

3. BFS 로 토마토 익히기

- queue에서 꺼낸 토마토의 위치 4방향을 탐색한다.

- 새로운 위치 && 안 익은 토마토 라면 익히고, visited, queue 업데이트한다.

 

4. visited 최댓값 return

- 안 익은 토마토가 있으면 -1


첫 번째 코드 : 시간 초과

function solution(m, n, graph) {
  // 기초 세팅 (방향(상하좌우), 방문처리(날짜+1), 큐(익어있는 토마토들의 위치))
  const dx = [-1, 1, 0, 0];
  const dy = [0, 0, -1, 1];
  let visited = Array.from({ length: n }, () => Array(m).fill(0)); // 날짜를 처리하는 곳
  let queue = []; // 익은 토마토들의 위치 담는 곳

  for (let i = 0; i < graph.length; i++) {
    for (let j = 0; j < graph[0].length; j++) {
      if (graph[i][j] === 1) {
        // 익은 토마토가 있는 경우
        queue.push([i, j]);
        visited[i][j] = 0;
      }
      if (graph[i][j] === -1) {
        // 토마토 없는 경우
        visited[i][j] = -1;
      }
    }
  }

  // bfs 탐색 : 1(익은 토마토) 탐색하기 - 익은 토마토가 여러개라서 시작점이 여러개.
  // 유효성 검사 (토마토가 없다.)
  while (queue.length > 0) {
    let [x, y] = queue.shift();

    for (let i = 0; i < 4; i++) {
      let nx = x + dx[i];
      let ny = y + dy[i];

      if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
      if (graph[nx][ny] === 0 && visited[nx][ny] === 0) {
        visited[nx][ny] = visited[x][y] + 1;
        queue.push([nx, ny]); // 안익은 토마토가 익었으니까 당연히 push!
      }
    }
  }

  let maxDay = 0;
  // 최댓값만 업데이트하는게 아닌, 0이 하나라도 있으면 -1을 반환해야한다. (다 익지 않았으므로)
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < m; j++) {
      if (visited[i][j] === 0 && graph[i][j] === 0) {
        return -1;
      }
      if (maxDay < visited[i][j]) {
        maxDay = visited[i][j];
      }
    }
  }
  return maxDay; // visited의 최댓값 반환
}

console.log(
  solution(6, 4, [
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 1],
  ])
); // 8

console.log(
  solution(6, 4, [
    [0, -1, 0, 0, 0, 0],
    [-1, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 1],
  ])
); // -1

console.log(
  solution(5, 5, [
    [-1, 1, 0, 0, 0],
    [0, -1, -1, -1, 0],
    [0, -1, -1, -1, 0],
    [0, -1, -1, -1, 0],
    [0, 0, 0, 0, 0, 0],
  ])
); // 14

문제 원인

queue.shift() 연산은 O(n)의 시간 복잡도를 가지고, 큐의 크기가 커지면 성능이 저하된다.

예를 들어, 1000x1000 크기의 토마토 상자에서 최악의 경우: 백만 개의 칸을 모두 방문할 수도 있다.

 

해결하기

1. queue.shift() 대신 인덱스를 사용한다.

========== 추가적으로 성능 최적화 ===========

2. 날짜 정보를 큐에 함께 저장 [x, y, day] 한다.

3. visited 배열은 방문 여부만 체크한다.


최종 코드

function solution1(m, n, graph) {
  const dx = [-1, 1, 0, 0];
  const dy = [0, 0, -1, 1];
  let visited = Array.from({ length: n }, () => Array(m).fill(0)); // 방문처리만!
  let queue = [];
  let maxDay = 0;

  for (let i = 0; i < graph.length; i++) {
    for (let j = 0; j < graph[0].length; j++) {
      if (graph[i][j] === 1) {
        queue.push([i, j, 0]);
      } else if (graph[i][j] === -1) {
        visited[i][j] = -1;
      }
    }
  }
  
  let idx = 0;
  while (idx < queue.length) {
    let [x, y, day] = queue[idx++];
    maxDay = Math.max(maxDay, day);

    for (let i = 0; i < 4; i++) {
      let nx = x + dx[i];
      let ny = y + dy[i];

      if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
      if (graph[nx][ny] === 0 && visited[nx][ny] === 0) {
        visited[nx][ny] = 1;
        queue.push([nx, ny, day + 1]);
      }
    }
  }

  for (let i = 0; i < n; i++) {
    for (let j = 0; j < m; j++) {
      if (graph[i][j] === 0 && !visited[i][j]) return -1;
    }
  }
  return maxDay;
}

 

 

'Coding Test > BackJoon' 카테고리의 다른 글

[백준 | node.js] 14502번: 연구소 BFS, DFS, 백트래킹 풀이  (0) 2025.01.31
'Coding Test/BackJoon' 카테고리의 다른 글
  • [백준 | node.js] 14502번: 연구소 BFS, DFS, 백트래킹 풀이
gitit
gitit
짬내서 쓰는 프론트엔드와 기술 메모 공간
  • gitit
    깃잇-gitit
    gitit
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Coding Test
        • Programmers
        • BackJoon
      • Development Tools
        • Firebase
        • Git
        • Monorepo
      • Programming
        • JavaScript
        • React
        • React-Native
      • etc.
        • GeekNews
        • Blockchain
      • Technical Interview
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    BFS
    긱뉴스
    리액트
    기본문법
    node.js
    React
    코딩테스트
    기술 질문
    javascript
    독학
    js
    프론트엔드
    frontend
    geeknews
    코딩
    modal
    매일메일
    알고리즘
    프로그래머스
    개발
    FE
    코테
    파이어베이스
    Firebase
    백준
    kakao
    styled-components
    파이썬
    AWS
    자바스크립트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
gitit
[백준 | node.js] 7576번: 토마토 BFS 풀이
상단으로

티스토리툴바