You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##AcWing 844. 走迷宫

一、题目描述

给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 01,其中 0 表示可以走的路,1 表示不可通过的墙壁。

最初,有一个人位于左上角 (1,1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。

请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。

数据保证 (1,1) 处和 (n,m) 处的数字为 0,且一定至少存在一条通路。

输入格式 第一行包含两个整数 nm

接下来 n 行,每行包含 m 个整数(01),表示完整的二维数组迷宫。

输出格式 输出一个整数,表示从左上角移动至右下角的最少移动次数。

数据范围 1≤n,m≤100

输入样例:

5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

输出样例:

8

二、理解与感悟

  1. bfs适合寻找最短(最长)的路径,因为是按层一层层找的,第一个符合条件的就是最短的路径。

  2. 走迷宫一般使用dx,dy,就是左上右下,或者上右下左的二组变量常数,在蛇形排列中,还强调了四个方向的初始化方向,在走迷宫时,不强调顺序,哪个方向先来都是一样的。

  3. 距离数组一般初始化为-1,表示未探索的位置。有时其它题中也表示不可以走的墙,具体问题再具体分析。

 memset(d,-1,sizeof d);

三、bfs解法

#include <bits/stdc++.h>

using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;

const int N = 110;
int n, m;
int g[N][N];
int d[N][N];

int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};

queue<PII> q;
int bfs() {
    q.push({1, 1});
    memset(d, -1, sizeof d);
    d[1][1] = 0;

    while (q.size()) {
        if (~d[n][m]) break; // 不等于-1,表示已找到小哈,剪枝
        auto u = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int tx = u.x + dx[i], ty = u.y + dy[i];
            if (tx == 0 || tx > n || ty == 0 || ty > m) continue;

            if (g[tx][ty] == 0 && d[tx][ty] == -1) {
                d[tx][ty] = d[u.x][u.y] + 1;
                q.push({tx, ty});
            }
        }
    }
    return d[n][m];
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> g[i][j];

    cout << bfs() << endl;
    return 0;
}

四、加强版练习

走迷宫升级版——边的权值不同

单点时限: 2.0 sec 内存限制: 256 MB

一天,sunny 不小心进入了一个迷宫,不仅很难寻找出路,而且有的地方还有怪物,但是 sunny 有足够的能力杀死怪物,但是需要一定的时间,但是 sunny想早一点走出迷宫,所以请你帮助他计算出最少的时间走出迷宫,输出这个最少时间

我们规定每走一格需要时间单位 1, 杀死怪物也需要时间 1, 如果不能走到出口,则输出 impossible. 每次走只能是上下左右 4 个方向。

输入格式 每次首先 2 个数 n,m (0<n,m≤200),代表迷宫的高和宽,然后 n 行,每行 m 个字符。

S 代码你现在所在的位置。 T 代表迷宫的出口。 # 代表墙,你是不能走的。 X 代表怪物。 . 代表路,可以走。 处理到文件结束。

输出格式 输出最少的时间走出迷宫。不能走出输出 impossible

输入样例:

输入样例:
4 4
S.X.
#..#
..#.
X..T
4 4
S.X.
#..#
..#.

输出样例:

6
impossible

(BFS + 优先队列) 题意:走迷宫,求最短路径,上下左右走一格花费1,走到有怪的格子花费2.

用户名:littlehb 密码:旧密码

思路

将每一点的坐标和由起点到该点的距离存入结构体. 由起点开始,将该点存入优先队列,以到起点的距离dis为优先级,每次取出dis最小的,向外扩散。 相当于第一轮得出所有到起点距离为1的点,第二轮得出所有到起点距离为2的点。 注意:对普通的最短路问题,由于每个各自的花费相同,因此每次存入的点优先级都相同. 故不需要使用优先队列,但本题存在有无怪物的区别,每次存入的格子的优先级可能不同,故使用优先队列。

#include <bits/stdc++.h>

using namespace std;
const int N = 210;

struct Node {
    int x, y; // 坐标
    int dis;  // 距离
    bool const operator<(const Node &b) const {
        return dis > b.dis;
    }
};
// 问:优先队列默认是大顶堆,如果想距离小的在前怎么办呢?
// 答:重载小于操作符。对比距离,谁的距离大谁就小。

char g[N][N];       // 地图
int sx, sy, tx, ty; // 起点坐标与终点坐标

int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
int n, m; // 代表迷宫的高和宽

void bfs() {
    priority_queue<Node> q; // 在priority_queue中优先队列默认是大顶堆
    Node st{sx, sy, 0};
    g[sx][sy] = '#';
    q.push(st);

    while (q.size()) {
        Node u = q.top();
        q.pop();
        // 若已找到,则退出
        if (u.x == tx && u.y == ty) {
            cout << u.dis << endl;
            return;
        }
        for (int i = 0; i < 4; i++) {
            int x = u.x + dx[i];
            int y = u.y + dy[i];
            Node t = {x, y, 0};

            if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] != '#') {
                if (g[x][y] == 'X')
                    t.dis = u.dis + 2;
                else
                    t.dis = u.dis + 1;
                // 走过就覆盖掉
                g[t.x][t.y] = '#';
                // 新结点入队列
                q.push(t);
            }
        }
    }
    // 没有结果,输出不可能到达
    printf("impossible\n");
}
int main() {
    while (cin >> n >> m) {
        for (int i = 0; i < n; i++) cin >> g[i]; // 按字符串读入
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) {
                if (g[i][j] == 'S') sx = i, sy = j;
                if (g[i][j] == 'T') tx = i, ty = j;
            }
        bfs();
    }
    return 0;
}