Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >蚂蚁走迷宫

蚂蚁走迷宫

作者头像
小K算法
发布于 2021-05-31 03:37:24
发布于 2021-05-31 03:37:24
1.7K00
代码可运行
举报
文章被收录于专栏:小K算法小K算法
运行总次数:0
代码可运行
01

故事起源

有一只蚂蚁出去寻找食物,无意中进入了一个迷宫。蚂蚁只能向上、下、左、右4个方向走,迷宫中有墙和水的地方都无法通行。这时蚂蚁犯难了,怎样才能找出到食物的最短路径呢?

02

思考

蚂蚁在起点时,有4个选择,可以向上、下、左、右某一个方向走1步。

如果蚂蚁走过了一段距离,此时也依然只有4个选择。 当然要排除之前走过的地方(不走回头路,走了也只会更长)和无法通过的墙和水。

蚂蚁想,还好我会影分身。如果每一步都分身成4个蚂蚁,向4个方向各走1步,这样最先找到食物的肯定就是最短的路径了(因为每一步都把能走的地方都走完了,肯定找不出更短的路径了)。

而且还能看出,第1步会到达所有到起点距离为1的地方,第2步也会到达所有距离为2的地方。 如此类推,第n步会覆盖所有到起点最短距离为n的地方。

03

问题建模

把迷宫地图放在二维数组中,能通行的地方为0,墙和水的地方为负数。

每一步向4个方向走,可以通过当前坐标加上一个方向向量。

这个其实就是宽度优先搜索(BFS)的思想。

04

宽度优先搜索(BFS)

又称广度优先搜索,优先向四周扩展子节点,是最简便的图的搜索算法之一,一般通过队列来实现。

4.1

队列

是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作,即先进先出。

队列一般通过数组实现,对该数组增加一些操作上的限制。

但上面的实现有一些缺陷,当队列满时,也就是tail指针移动到队尾,这时就无法再插入数据,但前面的元素已经出队了,可能还有空缺的位置。

为了能高效利用空间,对该队列增加一点改进,也就是循环队列的产生。

4.2

循环队列

把队列想象成一个首尾相接的环形。

数组实现,需要多预留一个空间。如果head=tail时,无法判断是队空还是队满,所以占用一个空间,通过tail+1与head的关系来判断是否队满。

4.3

队列实现BFS

实现步骤如下:

  • 将起点加入队列。
  • 从队首取出一个节点,通过该节点向4个方向扩展子节点,并依次加入队尾。
  • 重复以上步骤,直至队空或已找到目标位置。

回归迷宫问题,到起点的距离为1,2,3...的点会依次入队。

当head指针遍历到距离为2的点时,向4周扩展距离为3的节点,并继续入队。

05

代码实现

5.1

变量定义

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 方向向量
const int direction[4][2] = {{0,  1},
                             {-1, 0},
                             {0,  -1},
                             {1,  0}};

const int MAXM = 100, MAXN = 100, QUEUE_LENGTH = 5;
// 队列中的节点
struct Node {
    int x, y, distance;
    Node() {}
    Node(int xx, int yy, int d) : x(xx), y(yy), distance(d) {}
};

int n, m, step = 0, map[MAXM][MAXN], visit[MAXM][MAXN];
Node start, target;

5.2

BFS标准模板

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void bfs() {
    Node queue[QUEUE_LENGTH];
    int head = 0, tail = 1;
    queue[0] = Node(start.x, start.y, 0);
    visit[start.x][start.y] = 0;

    while (head != tail) {
        int x = queue[head].x;
        int y = queue[head].y;
        int distance = queue[head].distance;
        head = (head + 1) % QUEUE_LENGTH;
        for (int i = 0; i < 4; ++i) {
            int dx = x + direction[i][0];
            int dy = y + direction[i][1];
            if (dx >= 0 && dx < m && dy >= 0 && dy < n && visit[dx][dy] == -1 && map[dx][dy] >= 0) {
                // 表示从i方向走过来的,方便后续回溯路径
                visit[dx][dy] = i;
                if (dx == target.x && dy == target.y) {
                    cout << "已到目标点,最短距离为" << distance + 1 << endl;
                    step = distance + 1;
                    return;
                }
                if ((tail + 1) % QUEUE_LENGTH == head) {
                    cout << "队列满" << endl;
                    return;
                }
                // 新坐标入队
                queue[tail] = Node(dx, dy, distance + 1);
                tail = (tail + 1) % (QUEUE_LENGTH);
            }
        }
    }
}

5.3

路径回溯

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void printPath() {
    int x, y, d, path[MAXM][MAXN] = {0};
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            path[i][j] = -1;
        }
    }
    x = target.x;
    y = target.y;
    path[start.x][start.y] = 0;
    // 路径回溯
    while (!(x == start.x && y == start.y)) {
        path[x][y] = step--;
        d = visit[x][y];
        x -= direction[d][0];
        y -= direction[d][1];
    }
    // 路径打印
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            if (path[i][j] >= 0) {
                cout << path[i][j];
            } else {
                cout << "-";
            }
        }
        cout << endl;
    }
}

5.4

数据输入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main() {
    cin >> m >> n;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            cin >> map[i][j];
            visit[i][j] = -1;
        }
    }
    cin >> start.x >> start.y >> target.x >> target.y;
    bfs();
    if (step > 0) printPath();
    return 0;
}

5.5

测试结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
输入数据:
5 5
0 0 -1 0 0
0 0 0 0 -2
-1 0 -2 0 0
0 0 0 -1 0
0 -2 0 0 0
1 1 4 3

输出:
已到目标点,最短距离为5

路径打印:
-----
-0---
-1---
-23--
--45-
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小K算法 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Zoj 3865 Superbot
按规则移动机器人 , 问是否能拾得宝藏 。  加了一个控制板 , 还增加了一个控制板移动周期 p  将移动周期变换一下 , 移动一次  就相当于光标向左不耗费时间的移动了一格 搜索思路 : 搜索当前格子到上下左右四个格子所花费的最短时间 。 记录光标的信息 , 和当前格子所需最短时间 。 bfs + bfs 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define PI acos(-1.0) 4 #define MAXN 20
熙世
2019/07/15
3300
【多源BFS问题】01 矩阵
​ 给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。
利刃大大
2025/03/07
1070
【多源BFS问题】01 矩阵
走迷宫(BFS)
给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1 表示不可通过的墙壁。
GeekLiHua
2025/01/21
1570
使用 BFS 解决走迷宫问题
在一个由 0 和 1 构成的二维迷宫中,0 代表可以走的路径,而 1 代表墙或障碍物。任务是从迷宫的左上角出发,找到到达右下角的最短路径。这是计算机科学中的经典问题,对于理解图搜索和路径查找算法具有重要意义。
GeekLiHua
2025/01/21
1620
BFS算法模板与练习
上面过程可知,遍历的过程以及入队的过程都是按照BFS(1 2 3…10)的顺序进行的
timerring
2023/03/24
7350
BFS算法模板与练习
做题总结——走出迷宫
从起点开始,分别向上、下、左、右四个方向进行搜索,如果搜索到了终点,则说明能够到达终点;否则,将该点压入队列之中,继续进行下面的搜索,并将该点标记成已访问。
用户8224910
2021/01/26
6510
做题总结——走出迷宫
BFS广度优先遍历——Acwing 844. 走迷宫
我们可以将bfs当做一个成熟稳重的人,一个眼观六路耳听八方的人,他每次搜索都是一层层的搜索,从第一层扩散到最后一层,BFS可以用来解决最短路问题。
用户10604450
2024/03/15
1610
BFS广度优先遍历——Acwing 844. 走迷宫
献给阿尔吉侬的花束
今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。
GeekLiHua
2025/01/21
490
《算法竞赛进阶指南》0x25 广度优先搜索
在广度优先搜索的过程中,我们不断从队头取出状态,对于该状态面临的所有分支,把沿着每条分支到达的下一个状态(如果未访问过或者能够被更新成更优的解)插入队尾
一只野生彩色铅笔
2022/10/31
6760
《算法竞赛进阶指南》0x25 广度优先搜索
【leetcode】逐层探索:BFS求解最短路的原理与实践
在解决下面几道题之前,小编要展开讲讲为啥我们的BFS宽度优先遍历可以解决这里的最短路问题,我们在之前已经了解到,这个的宽度优先遍历BFS的遍历方法如同病毒扩散的方式进行扩散遍历,那么好就是一个关键
用户11288949
2025/05/18
1270
【leetcode】逐层探索:BFS求解最短路的原理与实践
1096. 地牢大师(BFS+三维数组)
地牢由若干个单位立方体组成,其中部分不含岩石障碍可以直接通过,部分包含岩石障碍无法通过。
浪漫主义狗
2022/07/11
3390
poj-3984-迷宫问题 (bfs 路径)
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 32323 Accepted: 18471
Cell
2022/02/25
3100
搜索(5)
 深度优先搜索一般是递归实现的,搜索过程中总是优先遍历当前节点的子节点。从这一节开始,我们将学习广(宽)度优先搜索  这个GIF图中,节点被染成绿色的顺序表示在宽度优先搜索过程中节点被访问的
mathor
2018/07/05
7890
P1141 01迷宫
题目描述 有一个仅由数字0与1组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上。 你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。 输入输出格式 输入格式: 输入的第1行为两个正整数n,m。 下面n行,每行n个字符,字符只可能是0或者1,字符之间没有空格。 接下来m行,每行2个用空格分隔的正整数i,j,对应了迷宫中第i行第j列的一个格子,询问从这一格开始能移动到多少格。 输出格式
attack
2018/04/13
1K0
算法:队列与广度优先搜索(迷宫问题)
本文介绍了迷宫问题以及广度优先搜索算法。迷宫由一个二维矩阵表示,其中0表示可以通行的道路,1表示墙壁。起点和终点用两个坐标列表表示。广度优先搜索从起点开始,每次从当前道路的所有可行走法中选择一个未探索过的方向进行探索,直到找到终点或者无法继续探索为止。相比深度优先搜索,广度优先搜索在求解迷宫问题时可以更快地找到最短路径,但需要更多的内存空间。
s1mba
2018/01/03
1.5K0
算法:队列与广度优先搜索(迷宫问题)
BFS:解决多源最短路问题
多源最短路问题(Multi-Source Shortest Path Problem,MSSP)是图论中的一个经典问题,它的目标是在给定图中找到从多个源点到所有其他顶点的最短路径。这个问题可以视为单源最短路问题(Single-Source Shortest Path Problem, SSSP)的扩展。 什么是单源最短路问题呢?其实我们上次讲的就可以归结在单元最短路问题当中,其实单源最短路问题就是只有一个起点对应一个终点,求最短路径,而多源最短路问题则是多个起点,对应一个终点,求这多个起点到达终点的最短路径,那这种题我们该怎么做呢? 第一种做法就是将多源最短路问题转换为n个单源最短路问题,循环n次就解决了,但是这种做法是非常慢的。 第二种做法就是把多个节点看成一个整体进行一次单源最短路问题的解法。 这是单源最短路问题问题:
用户11305458
2024/10/09
1650
BFS:解决多源最短路问题
迷宫的最短路径
题意:给定一个大小为N * M的迷宫,迷宫由通道与墙壁组成,每一步可以向邻接的上下左右四格的通道移动。请求出从起点到终点所需要的最下步数。
杨鹏伟
2020/09/14
1.1K0
数据结构与算法——BFS(广度优先搜索)
广度优先搜索(Breadth-First Search,简称BFS)是一种遍历或搜索树和图的算法,也称为宽度优先搜索,BFS算法从图的某个节点开始,依次对其所有相邻节点进行探索和遍历,然后再对这些相邻节点的相邻节点进行探索,直到遍历完所有的节点。BFS算法使用队列来辅助实现,将起始节点放入队列中,然后依次取出队列中的节点,访问其相邻节点,并将其加入队列。这样可以保证从起始节点出发,依次按照距离顺序遍历节点。BFS常用于寻找最短路径,因为它按照从起点到每个节点的距离来探索节点。
摆烂小白敲代码
2024/09/23
3630
数据结构与算法——BFS(广度优先搜索)
NC14572 走出迷宫
小明的起点在地图中用“S”来表示,终点用“E”来表示,障碍物用“#”来表示,空地用“.”来表示。 障碍物不能通过。小明如果现在在点(x,y)处,那么下一步只能走到相邻的四个格子中的某一个:(x+1,y),(x-1,y),(x,y+1),(x,y-1);
浪漫主义狗
2022/07/11
1990
走迷宫(bfs, 最短路)
Input 10 10 #S######.# ......#..# .#.##.##.# .#........ ##.##.#### ....#....# .#######.# ....#..... .####.###. ....#...G# ---- Output 22 ---- 代码: #include<iostream> #include<cstring> #include<queue> using namespace std; typedef pair<int, int> P; queue<P> p
_DIY
2019/09/11
8320
走迷宫(bfs, 最短路)
相关推荐
Zoj 3865 Superbot
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验