top1编程
← 返回题目
题解

森林探险

1 条题解

  • 0
    @ 2026-8-7 16:01:05

    P4897 森林探险(入门)

    解题思路

    第一步,读懂题目。 小童在 n×n 的迷宫里走,'.' 是可以走的路,'#' 是障碍物不能走。他只能上下左右走,问能不能从起点 A 走到终点 B。地图左上角是 (1,1)。如果起点或终点本身是 '#',直接算走不到。题目给 t 组数据,每组都要回答一次。

    第二步,用深搜探路。 从起点 (sx,sy) 出发,往四个方向试探:能走的路('.')就走进去,继续往前探;走不通就退回来换方向。只要某条路走到了终点 (ex,ey),就说明能办到。

    第三步,防止死循环。 走过的路要立刻改成 '#',表示"这条路已经试过了",不然会在迷宫里面转圈出不来。因为 '#' 本来就不能走,改成 '#' 正好拦住回头路。

    第四步,处理特殊要求。 题目特别强调:如果起点或者终点有一个是 '#',就看成无法办到。所以深搜之前要先检查这两个点。另外每组数据都要重新读入地图并重置答案,所以 ok 标记要在每组开头清零。

    具体例子: 第一组 3×3 迷宫,从 (1,1) 到 (3,3) 有条路能走通,输出 YES;第二组 5×5 迷宫被 # 挡住了,走不到,输出 NO。

    边界情况: t 和 n 最大都是 50,一组迷宫最多 2500 个格子,深搜完全来得及。注意读地图时是一行一个字符串,用字符方式逐个读入即可。

    参考代码

    // 森林探险:t组迷宫,判断起点能否走到终点,.可走#不可走
    #include <iostream>
    using namespace std;
    
    int n, sx, sy, ex, ey, ok;
    char g[55][55]; // 迷宫地图
    int dx[4] = {-1, 1, 0, 0};
    int dy[4] = {0, 0, -1, 1};
    
    // 从(x,y)向上下左右深搜
    void dfs(int x, int y) {
        if (x == ex && y == ey) { ok = 1; return; }
        g[x][y] = '#'; // 走过标记为不可走
        for (int k = 0; k < 4; k++) {
            int nx = x + dx[k], ny = y + dy[k];
            if (nx >= 1 && nx <= n && ny >= 1 && ny <= n && g[nx][ny] == '.' && !ok)
                dfs(nx, ny);
        }
    }
    
    int main() {
        int t;
        cin >> t;
        while (t--) {
            cin >> n;
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    cin >> g[i][j];
            cin >> sx >> sy >> ex >> ey;
            ok = 0;
            if (g[sx][sy] == '#' || g[ex][ey] == '#')
                cout << "NO" << endl; // 起点或终点不可走
            else {
                dfs(sx, sy);
                cout << (ok ? "YES" : "NO") << endl;
            }
        }
        return 0;
    }
    

    复杂度分析

    每组数据每个格子最多被访问一次,时间复杂度是 O(t×n²)。t、n 最大都是 50,也就是最多 50×2500=125000 个格子,很快。空间上需要存一张 n×n 的地图,是 O(n²)。

    • 1