【中等】算法nodeJs:迷宫问题

182 阅读2分钟

描述

有一个 h 行 w 列的网格,我们使用 (i,j) 表示网格中从上往下数第 i 行和从左往右数第 j 列的单元格。每个方格要么是可以通过的空方格 ‘0’ ,要么是不可通过的墙方格 ‘1’ ,特别的,网格的四周都是墙方格,你可以沿着空方格上下左右随意移动:从 (x,y) 向上移动一格即抵达 (x−1,y) 、向下移动一格即抵达 (x+1,y) 、向左移动一格即抵达 (x,y−1) 、向右移动一格即抵达 (x,y+1) 。

现在,你位于迷宫的入口 (0,0) ,想要前往终点 (h−1,w−1) 。请输出一条从起点到终点的可行路径。

保证起点和终点一定为空方格,你始终可以找到且能唯一找到一条从起点出发到达终点的可行路径。

输入描述:

第一行输入两个整数 h,w(1≦h,w≦100) 代表迷宫的行数和列数。
此后 h 行,第 i 行输入 w 个整数 ai,1​,ai,2​,…,ai,w​(0≦ai,j​≦1) 代表迷宫的布局。其中,ai,j​=0 表示单元格 (i,j) 是空方格,ai,j​=1 表示单元格 (i,j) 是墙方格。

输出描述:

输出若干行,第 i 行输出两个整数 xi​,yi​ ,表示路径的第 i 步抵达的单元格坐标为 (xi​,yi​) 。

你需要保证输出的路径是符合题目要求的,即从起点 (0,0) 出发,到达终点 (h−1,w−1) ,且路径上每个单元格都是空方格,行走的单元格都是彼此相邻的。

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
    // Write your code here
    const [h, w] = (await readline()).split(" ").map(Number); // 迷宫的行数和列数
    const maze = []; // 迷宫的布局
    for (let i = 0; i < h; i++) {
        maze.push((await readline()).split(" ").map(Number));
    }
    // 定义方向数组:上、下、左、右
    const directions = [
        [-1, 0], // 上
        [1, 0], // 下
        [0, -1], // 左
        [0, 1], // 右
    ];

    // 初始化 visited 和 parent 数组
    const visited = Array.from({ length: h }, () => Array(w).fill(false));
    const parent = Array.from({ length: h }, () => Array(w).fill(null));
    // BFS 队列
    const queue = [];
    queue.push([0, 0]); // 起点
    visited[0][0] = true;
    // BFS 搜索
    let found = false;
    while (queue.length > 0 && !found) {
        const [x, y] = queue.shift(); // 取出队首节点

        // 遍历四个方向
        for (const [dx, dy] of directions) {
            const nx = x + dx; // 新节点的行
            const ny = y + dy; // 新节点的列

            // 检查新节点是否合法
            if (
                nx >= 0 &&
                nx < h &&
                ny >= 0 &&
                ny < w &&
                maze[nx][ny] === 0 &&
                !visited[nx][ny]
            ) {
                visited[nx][ny] = true; // 标记为已访问
                parent[nx][ny] = [x, y]; // 记录父节点
                queue.push([nx, ny]); // 加入队列

                // 如果到达终点,结束搜索
                if (nx === h - 1 && ny === w - 1) {
                    found = true;
                    break;
                }
            }
        }
    }

    // 回溯路径
    const path = [];
    let [x, y] = [h - 1, w - 1]; // 从终点开始
    while (x !== 0 || y !== 0) {
        path.push([x, y]); // 加入路径
        [x, y] = parent[x][y]; // 回溯到父节点
    }
    path.push([0, 0]); // 加入起点

    // 反转路径,得到从起点到终点的路径
    path.reverse();

    // 输出路径
    for (const [x, y] of path) {
        console.log(`(${x},${y})`);
    }
})();