洛谷B3625迷宫寻路

迷宫寻路

题目描述

机器猫被困在一个矩形迷宫里。

迷宫可以视为一个 n × m n\times m n×m 矩阵,每个位置要么是空地,要么是墙。机器猫只能从一个空地走到其上、下、左、右的空地。

机器猫初始时位于 ( 1 , 1 ) (1, 1) (1,1) 的位置,问能否走到 ( n , m ) (n, m) (n,m) 位置。

输入格式

第一行,两个正整数 n , m n,m n,m

接下来 n n n 行,输入这个迷宫。每行输入一个长为 m m m 的字符串,# 表示墙,. 表示空地。

输出格式

仅一行,一个字符串。如果机器猫能走到 ( n , m ) (n, m) (n,m),则输出 Yes;否则输出 No

样例 #1

样例输入 #1

3 5
.##.#
.#...
...#.

样例输出 #1

Yes

提示

样例解释

路线如下: ( 1 , 1 ) → ( 2 , 1 ) → ( 3 , 1 ) → ( 3 , 2 ) → ( 3 , 3 ) → ( 2 , 3 ) → ( 2 , 4 ) → ( 2 , 5 ) → ( 3 , 5 ) (1,1)\to (2,1) \to (3,1) \to (3,2)\to (3,3) \to (2, 3) \to (2, 4) \to (2, 5) \to (3, 5) (1,1)(2,1)(3,1)(3,2)(3,3)(2,3)(2,4)(2,5)(3,5)

数据规模与约定

对于 100 % 100\% 100% 的数据,保证 1 ≤ n , m ≤ 100 1 \leq n, m \leq 100 1n,m100,且 ( 1 , 1 ) (1,1) (1,1) ( n , m ) (n, m) (n,m) 均为空地。

运用bfs来解决
一开始机器猫在(0,0)位置,要走到(n-1,m-1)位置
边界条件:x、y大于0且分别小于n、m,每一点都只能走一次(通过bool数组记载是否走过),下一次要走的位置上不是#。

#include<bits/stdc++.h>
using namespace std;int n,m;
const int N = 110;
char path[N][N];
bool st[N][N];
int X[4] = {-1,0,1,0};
int Y[4] = {0,-1,0,1};bool bfs()
{//BFS使用一个队列来存储待访问的节点。//队列的特性是先进先出(FIFO),这确保了BFS是逐层访问节点的。queue<pair<int,int>> q;//创建一个队列来存储待访问节点q.push({0,0});//将起始节点(0,0)入队st[0][0] = true;//标记起始节点为已访问while(!q.empty())//当队列不为空时,继续搜索{int x = q.front().first;//取出队列中的第一个节点的坐标int y = q.front().second;q.pop();//弹出队列中的第一个节点if(x == n-1 && y == m-1)//如果当前节点是目标节点,则返回 true{return true;}//遍历当前节点的四个相邻方向for(int i = 0;i < 4;i++){int dx = x + X[i];//计算新节点的 x 坐标int dy = y + Y[i];//计算新节点的 y 坐标//检查新节点是否在网格范围内、是否未被访问过、以及是否是可通过的节点if(dx >= 0 && dy >= 0 && dx < n&& dy < m && !st[dx][dy] && path[dx][dy] != '#'){st[dx][dy] = true;//标记新节点为已访问q.push({dx,dy});//将新节点加入队列,以便后续访问它的相邻节点}}}return false;//如果队列为空且没有找到目标节点,则返回 false
}int main()
{cin >> n >> m;for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){cin >> path[i][j];st[i][j] = false;}}if(bfs()){cout << "Yes" <<endl;}else{cout << "No" <<endl;}return 0;
}

扩展

获取单一行走路径:

#include<bits/stdc++.h>
using namespace std;int n, m;
const int N = 110;
char path[N][N];
bool st[N][N];
pair<int, int> previous[N][N]; // 用于记录每个节点的父节点
int X[4] = {-1, 0, 1, 0};
int Y[4] = {0, -1, 0, 1};bool bfs() {queue<pair<int, int>> q;q.push({0, 0});st[0][0] = true;while (!q.empty()) {int x = q.front().first;int y = q.front().second;q.pop();if (x == n - 1 && y == m - 1) {return true; // 找到目标节点,返回true表示找到路径}for (int i = 0; i < 4; i++) {int dx = x + X[i];int dy = y + Y[i];if (dx >= 0 && dy >= 0 && dx < n && dy < m && !st[dx][dy] && path[dx][dy] != '#') {st[dx][dy] = true;previous[dx][dy] = {x, y}; // 记录父节点q.push({dx, dy});}}}return false; // 无法到达目标节点
}void printPath() {int x = n - 1, y = m - 1;vector<pair<int, int>> path;// 回溯到起点,构建路径while (x != 0 || y != 0) {path.push_back({x, y});pair<int, int> p = previous[x][y];x = p.first;y = p.second;}path.push_back({0, 0}); // 添加起点// 打印路径(从起点到终点)for (int i = path.size() - 1; i >= 0; i--) {cout << "(" << path[i].first << "," << path[i].second << ") ";}cout << endl;
}int main() {cin >> n >> m;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> path[i][j];st[i][j] = false;previous[i][j] = {-1, -1}; // 初始化为无效值}}if (bfs()) {cout << "Yes" << endl;printPath(); // 打印路径} else {cout << "No" << endl;}return 0;
}

在这段代码中,增加了一个previous数组来记录每个节点的父节点。当找到目标节点时,bfs函数返回true,然后调用printPath函数来回溯并打印出从起点到终点的路径。
bfs部分详解:

void printPath() {  int x = n - 1, y = m - 1; // 从终点开始回溯  vector<pair<int, int>> path; // 用于存储路径上的节点坐标  // 回溯到起点,构建路径  while (x != 0 || y != 0) { // 当还没有回溯到起点时继续循环  path.push_back({x, y}); // 将当前节点坐标添加到路径中  pair<int, int> p = previous[x][y]; // 获取当前节点的父节点坐标  x = p.first; // 更新x坐标为父节点的x坐标  y = p.second; // 更新y坐标为父节点的y坐标  }  path.push_back({0, 0}); // 添加起点到路径中,因为上面的循环条件导致起点不会被添加  // 打印路径(从起点到终点),注意这里是从后往前打印,因为路径是从起点开始记录的  for (int i = path.size() - 1; i >= 0; i--) {  cout << "(" << path[i].first << "," << path[i].second << ") "; // 打印每个节点的坐标  }  cout << endl; // 打印换行  
}

printPath 函数是用于打印从起点(0,0)到终点(n-1, m-1)在迷宫中的具体路径的。这个函数通过回溯的方式,利用在广度优先搜索(BFS)过程中记录的每个节点的父节点信息,来重建整条路径。

这个函数的工作流程如下:

  1. 初始化终点坐标 (x, y)(n-1, m-1)
  2. 创建一个空的 vector 容器 path,用于存储路径上的节点坐标。
  3. 使用 while 循环进行回溯,条件是当前节点不是起点(即 x != 0 || y != 0)。
    • 在循环中,首先将当前节点的坐标 (x, y) 添加到 path 中。
    • 然后,通过查询 prev 数组获取当前节点的父节点坐标,并将父节点坐标赋值给 (x, y),以便在下一次循环中继续回溯。
  4. 循环结束后,将起点坐标 (0, 0) 添加到 path 中,因为回溯过程是从终点开始,到起点结束,但由于循环条件的限制,起点并未被包含在内,所以需要手动添加。
  5. 最后,使用 for 循环逆序打印 path 中的节点坐标。这是因为路径在 path 中是以从终点到起点的顺序存储的,而我们需要按照从起点到终点的顺序打印出来。

通过这个函数,我们就可以在控制台上看到从起点到终点的完整路径了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/655029.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

web渗透测试-Server2225-(环境+解析)

1、访问目标IP,打开第1题,根据页面提示,将获取的flag提交。提交格式:flag{xxx}(提交花括号里面的字段) 给出了如上代码,很明显,flag在flag.php文件内。 REQUEST方法既可以接受GET方法,也可以接受POST方法,方便起见,我们选择GET方法。 eval函数 eval() 函数把字符串…

电商平台低价乱价?电商平台API接口接入,实时获取商品价格

​和传统线下渠道对比线上电商运营手段多样和方便&#xff0c;电商会经常采用价格策略以吸引消费者&#xff0c;这种灵活而频繁的价格变动对供货商的渠道管理提出了前所未有的挑战&#xff0c;实时监测电商的价格变动对于品牌商和电商平台是非常重要的环节。而促销活动设计和日…

Did We Get Everything Covered? Codeforces Round 921 (Div. 2) 1925C

Problem - C - Codeforces 题目大意&#xff1a;给出一个长度为m的字符串s&#xff0c;问所有长度为n且由字母表中前k个字母组成的字符串是否都是s的子序列&#xff0c;如果不是须给出反例 1<n<26;1<k<26;1<m<1000;所有样例的m之和不超过1e6 思路&#xf…

MySQL事务和锁05

官网地址&#xff1a;MySQL :: MySQL 5.7 Reference Manual :: 13.3.6 SET TRANSACTION Statement 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. Mysql5.7参考手册 / ... / 集事务语句 13.3.6设定交易报表 …

当包容结构体遇见灵活的内存管理

&#x1f308;个人主页&#xff1a;小田爱学编程 &#x1f525; 系列专栏&#xff1a;c语言从基础到进阶 &#x1f3c6;&#x1f3c6;关注博主&#xff0c;随时获取更多关于c语言的优质内容&#xff01;&#x1f3c6;&#x1f3c6; &#x1f600;欢迎来到小田代码世界~ &#x…

Python算法题集_和为K的子数组

本文为Python算法题集之一的代码示例 题目560&#xff1a;和为K的子数组 说明&#xff1a;给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1&#xff1a; 输入&#xff1a;nu…

Revit2018复现《AUTODESK REVIT二次开发基础教程》代码17

using Autodesk.Revit.Attributes; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LearnTime { //必备写法 [Transaction(Tr…

JavaScript DOM属性和方法之event事件对象

event对象代表事件的状态&#xff0c;比如事件在其中发生的元素&#xff0c;键盘按键的状态、鼠标的位置、鼠标按钮的状态&#xff0c;事件通常与函数结合使用&#xff0c;函数不会在事件发生前被执行&#xff0c;只有当事件被触发的时候才会执行函数。 一、句柄事件 HTML5的…

【代码能力提升 | 代码阅读学习】分析 VoxelNet 的 主干

文章目录 前言代码分析VoxelNet model2.数据处理2.1单个样本处理2.2处理成batch 最后&#xff0c;附上我一步步调试代码&#xff0c;到3D-conv 前言 代码来自&#xff1a;https://github.com/skyhehe123/VoxelNet-pytorch 其中 测试数据来自&#xff1a;https://github.com/ga…

Go语言标准库log日志

Go语言内置的log包实现了简单的日志服务。 使用Logger log包定义了Logger类型&#xff0c;该类型提供了一些格式化输出的方法。本包也提供了一个预定义的“标准”logger&#xff0c;可以通过调用函数Print系列(Print|Printf|Println&#xff09;、Fatal系列&#xff08;Fatal…

Mysql查询优化从入门到入土详解含示例(值得珍藏)

点击下载《Mysql查询优化从入门到入土详解含示例&#xff08;值得珍藏&#xff09;》 1. 前言 随着互联网的快速发展&#xff0c;数据库已经成为应用程序的重要组成部分。MySQL作为最流行的关系型数据库管理系统之一&#xff0c;广泛应用于各种场景。然而&#xff0c;随着数据…

春节寄快递贵?想要便宜寄快递?那是你没找到寄快递便宜的渠道!

春节将至&#xff0c;公司会发放一大批的年货礼品给员工们&#xff0c;来聊表这一年来的勤恳工作的心意。但是想要拿走这么多的年货&#xff0c;可不是一件容易的事情啊&#xff0c;这时候我们可以通过邮寄的方式把东西邮寄走&#xff0c;是不是省了很多事呢&#xff0c;不仅回…

如何过有「松弛感」的生活?

最近网上有一个词很流行&#xff0c;叫做「松弛感」。最早的出处似乎是这么一条微博&#xff1a;博主见到一家人出门旅游&#xff0c;行李全部被退回&#xff0c;空手抵达目的地&#xff0c;竟然没人紧张和生气&#xff0c;而是重新安排好行李后继续开心聊天&#xff0c;全程非…

Redis -- 前置知识

目录 简要 分布式系统 负载均衡 引入缓存 数据库分表 微服务 小结 简要 redis是存储数据在内存中, 定义变量就是在内存中, 但是redis是在分布式系统中, 才能真正发挥威力, 如果只是单机程序, 那么直接通过变量来存储数据的方式将是最优的选择. …

Unity 解释器模式(实例详解)

文章目录 示例1&#xff1a;基础解释器结构示例2&#xff1a;小于表达式&#xff08;LessThanExpression&#xff09;示例3&#xff1a;逻辑或表达式&#xff08;OrExpression&#xff09;示例4&#xff1a;逻辑非表达式&#xff08;NotExpression&#xff09;示例5&#xff1a…

DeepLearningSystem:开启深度学习之旅的全方位指南,一款深度学习系统性开源课程项目!

在当今这个数据驱动的时代&#xff0c;深度学习技术 已经成为了科技领域的一个重要分支。 对于有志于掌握这一技术的专业人士和学生来说&#xff0c;有一个项目值得特别关注——由chenzomi12开发的“深度学习系统”课程。 Star&#xff1a;6.2k GitHub&#xff1a;https://gi…

美睫师睫毛嫁接零基础学习,日式美睫与开花嫁接实战教学

一、教程描述 大家都说女人的钱好挣&#xff0c;这是因为每个女人在每年&#xff0c;都要花很多钱来打扮自己。本套教程是关于日式美睫和开花嫁接的&#xff0c;从零基础学习到店铺经营都有涉及&#xff0c;就做美睫和睫毛嫁接这两项业务&#xff0c;月收入万元以上应该问题不…

系统引导程序 Boot Loader——学习笔记

基于嵌入式Linux 的完整系统软件由三个部分组成&#xff1a;系统引导程序、Linux 操作系统内核和文件系统。 系统引导程序 Boot Loader 是系统加电后运行的第一段软件代码&#xff0c;它的作用是加载操作系统或者其他程序到内存中&#xff0c;并将控制权交给它们。 Boot Load…

JMeter性能测试实战

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

C语言——O / 动态内存管理

一、为什么要有动态内存分配 我们已经掌握的内存开辟⽅式有&#xff1a; int val 20;//在栈空间上开辟四个字节 char arr[10] {0};//在栈空间上开辟10个字节的连续空间 但是上述的开辟空间的⽅式有两个特点&#xff1a; • 空间开辟⼤⼩是固定的。 • 数组在申明的时候&am…