문제

1,1부터 출발해서 마지막 칸까지 가는데 필요한 최소 칸 수를 구하는 문제이다. 전형적인 그래프 탐색 문제이다. dfs로 풀게 되면 자기가 들어갈 수 있는 만큼 계속 안쪽으로 먼저 파고들면서 탐색하는게 선행되기 때문에 최소거리는 구하기 힘들다. 그러므로 bfs로 탐색하는게 더 효과적이다.

const INPUT_FILE = process.platform === "linux" ? "/dev/stdin" : "./inputs.txt";
const [f, ...maps] = require("fs")
  .readFileSync(INPUT_FILE)
  .toString()
  .trim()
  .split("\n");
 
const [n, m] = f.split(" ").map(Number);
const maze = maps.map((m) => Array.from(m));
const visited = Array.from({ length: n }, () => new Array(m).fill(false));
const dLoc = [
  [-1, 0],
  [1, 0],
  [0, 1],
  [0, -1],
];
 
function bfs() {
  const queue = [[0, 0, 1]];
  while (queue.length) {
    const [x, y, cnt] = queue.shift();
    if (x === n - 1 && y === m - 1) {
      console.log(cnt);
      return;
    }
    visited[x][y] = true;
 
    for (const [dx, dy] of dLoc) {
      const nx = x + dx;
      const ny = y + dy;
      if (
        nx >= 0 &&
        nx < n &&
        ny >= 0 &&
        ny < m &&
        !visited[nx][ny] &&
        maze[nx][ny] === "1"
      ) {
        queue.push([nx, ny, cnt + 1]);
      }
    }
  }
}
 
bfs();

처음에는 이렇게 했었다. 하지만 이상하게도 시간 초과가 났다. 방문 처리도 잘 했고, 큐에 배열을 넣는 것까지 문제 없다고 생각했다. 하지만 여기에서 문제는 방문처리에 있었다. while문을 돌면서 queue에서 빼낼 때 방문 처리를 하게 되면 dLoc을 돌면서 새로운 경로를 추가할 때는 visited 배열이 갱신되기 전이기 때문에 방문할 예정인 노드 또한 다시 추가되는 문제가 생긴다.

const INPUT_FILE = process.platform === "linux" ? "/dev/stdin" : "./inputs.txt";
const [f, ...maps] = require("fs")
  .readFileSync(INPUT_FILE)
  .toString()
  .trim()
  .split("\n");
 
const [n, m] = f.split(" ").map(Number);
const maze = maps.map((m) => Array.from(m));
const visited = Array.from({ length: n }, () => new Array(m).fill(false));
const dLoc = [
  [-1, 0],
  [1, 0],
  [0, 1],
  [0, -1],
];
 
function bfs() {
  const queue = [[0, 0, 1]];
  visited[0][0] = true;
 
  while (queue.length) {
    const [x, y, cnt] = queue.shift();
    if (x === n - 1 && y === m - 1) {
      console.log(cnt);
      return;
    }
 
    for (const [dx, dy] of dLoc) {
      const nx = x + dx;
      const ny = y + dy;
      if (
        nx >= 0 &&
        nx < n &&
        ny >= 0 &&
        ny < m &&
        !visited[nx][ny] &&
        maze[nx][ny] === "1"
      ) {
        visited[nx][ny] = true;
        queue.push([nx, ny, cnt + 1]);
      }
    }
  }
}
 
bfs();

이를 해결하기 위해서 새로운 경로를 추가할 때 미리 visited 배열을 갱신해주었다.

경로의 방문 처리는 항상 신경 써서 풀자 !