迷宫

GitHub跳转原题关系图返回列表

把迷宫可达性转成网格图连通性,从 A 出发用入栈即标记的 visited 做一次迭代 DFS,O(n²) 判断 B 是否同属一个连通分量。

OJ: roj

题目 ID: 1215

难度:普及-

标签:搜索深度优先搜索网格python

创建: 2026-09-29 23:49

更新: 2026-10-05 05:42

题目描述

n×n(1≤n≤100)网格迷宫,每格 . 可走 / # 障碍;只能上下左右四方向相邻移动到 .。Extense 要从 A 走到 B(均 0 起始坐标),起点或终点为 # 视为不能。k 组输入:每组先 n,再 n 行矩阵,再 ha la hb lb;每组输出一行 YES/NO。

思路

把每个 . 看顶点、四方向相邻 . 连边,A→B 可达即二者同属一个连通分量。从 A 做一次带 visited 的迭代 DFS(显式栈),入栈即标记,弹到 B 返回 YES、栈空返回 NO,每组 O(n²)。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-29 23:54
# update_at: 2026-09-29 23:54

import sys

DIRS = ((-1, 0), (1, 0), (0, -1), (0, 1))  # 上、下、左、右四个相邻方向


def reachable(maze: list[str], ha: int, la: int, hb: int, lb: int) -> bool:
    """能否从 A(ha, la) 走到 B(hb, lb):只经 '.'、四方向相邻;A、B 任一是 '#' 直接不通。"""
    n = len(maze)
    if maze[ha][la] == '#' or maze[hb][lb] == '#':
        return False
    a, b = (ha, la), (hb, lb)
    seen = {a}
    stack = [a]
    while stack:
        cell = stack.pop()
        if cell == b:
            return True
        r, c = cell
        for dr, dc in DIRS:
            nr, nc = r + dr, c + dc
            # 先判在界内,短路顺序保证不会越界读 maze
            can_go = 0 <= nr < n and 0 <= nc < n and maze[nr][nc] == '.' and (nr, nc) not in seen
            if can_go:
                seen.add((nr, nc))  # 入栈即标记,防止同一点被重复展开成环
                stack.append((nr, nc))
    return False


def solve() -> None:
    data = iter(sys.stdin.buffer.read().split())
    out: list[str] = []
    k = int(next(data))  # 测试数据组数

    for _ in range(k):
        n = int(next(data))  # 迷宫规模 n * n
        maze = [next(data).decode() for _ in range(n)]
        ha, la, hb, lb = (int(next(data)) for _ in range(4))  # A、B 的行列,均从 0 开始
        can_walk = reachable(maze, ha, la, hb, lb)
        out.append('YES' if can_walk else 'NO')

    print('\n'.join(out))


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-05 05:42
 * update_at: 2026-10-05 05:45
 */
//
// main.cpp:roj 1215 迷宫
// 解法:从 A 出发做一次带 visited 的迭代 DFS(显式栈模拟),
//       每入栈即标记,弹到 B 返回 YES、栈空返回 NO。
//       A 或 B 是 '#' 直接判 NO;每组 O(n²),n ≤ 100。
//
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MAXN = 105; // n ≤ 100,留一点余量

char grid[MAXN][MAXN];   // 当前迷宫的 '.', '#' 网格
bool seen[MAXN][MAXN];   // 标记:本次搜索中该格是否已经入过栈
int dr[4] = {-1, 1, 0, 0}; // 上下左右四个方向偏移
int dc[4] = {0, 0, -1, 1};

// 在界内 且 落点是 '.' 且 未访问过,三条同时满足才能扩展。
bool can_go(int nr, int nc, int n) {
    return nr >= 0 && nr < n && nc >= 0 && nc < n
        && grid[nr][nc] == '.' && !seen[nr][nc];
}

// 从 A(ha, la) 出发做迭代 DFS,判断能否到达 B(hb, lb)。
bool reachable(int n, int ha, int la, int hb, int lb) {
    if (grid[ha][la] == '#' || grid[hb][lb] == '#') {
        return false; // 起点或终点是障碍直接判否
    }
    // 清空 seen:本组最多用 n×n 这么大,只需清理 [0,n)×[0,n)
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            seen[i][j] = false;
        }
    }

    // 显式栈保存 (r, c);压栈前先标记,避免同一点被重复展开。
    pair<int,int> stk[MAXN * MAXN];
    int top = 0;
    stk[top++] = {ha, la};
    seen[ha][la] = true;

    while (top > 0) {
        pair<int,int> cur = stk[--top];
        if (cur.first == hb && cur.second == lb) {
            return true;
        }
        for (int k = 0; k < 4; k++) {
            int nr = cur.first + dr[k];
            int nc = cur.second + dc[k];
            if (can_go(nr, nc, n)) {
                seen[nr][nc] = true; // 入栈即标记
                stk[top++] = {nr, nc};
            }
        }
    }
    return false;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int k;
    if (!(cin >> k)) return 0;
    for (int t = 0; t < k; t++) {
        int n;
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> grid[i];
        }
        int ha, la, hb, lb;
        cin >> ha >> la >> hb >> lb;
        bool ok = reachable(n, ha, la, hb, lb);
        cout << (ok ? "YES" : "NO") << "\n";
    }
    return 0;
}