从迷宫问题理解dfs

文章目录

  • 迷宫问题打印路径1
    • 思路
      • 定义一个结构体
      • 要保存所走的路径,就需要使用到栈
      • 遍历所有的可能性
      • 核心代码
    • 部分函数递归图
    • 源代码
  • 迷宫问题返回最短路径
    • 这里的思想同上面类似。
    • 源代码

迷宫问题打印路径1

定义一个二维数组 N*M ,如 5 × 5 数组下所示:

int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。

输入描述:
输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的1表示墙壁,0表示可以走的路。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。

输出描述:
左上角到右下角的最短路径
输入:
5 5
0 1 0 0 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出:
(0,0)
(1,0)
(2,0)
(2,1)
(2,2)
(2,3)
(2,4)
(3,4)
(4,4)

思路

定义一个结构体

typedef struct pt {//行·int row;//列int col;
}PT;

要保存所走的路径,就需要使用到栈

  导入c++的 STL栈。
如果是c语言就需要自己手写栈。
c语言的栈

遍历所有的可能性

在这里插入图片描述

核心代码

  遍历上,右,左,下四个方向。先上核心代码。

bool isPath(int** a, int n, int m, PT pt)
{if (pt.row >= 0 && pt.row < n&& pt.col >= 0 && pt.col < m&& a[pt.row][pt.col] == 0){return true;}else {return false;}
}//这里只需要一条路,直接返回bool值
bool dfs(int** a, int n, int m, PT pt)
{st.push(pt);if (pt.row == n - 1 && pt.col == m - 1){//找到出口return true;}//标记走过的路为2a[pt.row][pt.col] = 2;//开始遍历四个方向//上PT next = pt;next.row -= 1;if (isPath(a, n, m, next)){if (dfs(a, n, m, next)){return true;}}//右next.row += 1;next.col += 1;if (isPath(a, n, m, next)){if (dfs(a, n, m, next)){return true;}}//下next.col -= 1;next.row += 1;if (isPath(a, n, m, next)){if (dfs(a, n, m, next)){return true;}}//左next.row -= 1;next.col -= 1;if (isPath(a, n, m, next)){if (dfs(a, n, m, next)){return true;}}st.pop();//四个方向都不行,则false;return false;
}

部分函数递归图

开始按照每个点的上,右,左,下开始前进,如果可以走,则进行标记为2,如果一个方向不可以走,则换另一个方向,直到四个方向都不可以走,则返回上一个正确的位置。
在这里插入图片描述

源代码

// https://www.nowcoder.com/practice/cf24906056f4488c9ddb132f317e03bc?tpId=37&tqId=21266&ru=/exam/oj#include <iostream>
using namespace std;
#include<stack>typedef struct pt {int row;int col;
}PT;stack<PT> st;bool isPath(int** a, int n, int m, PT pt)
{if (pt.row >= 0 && pt.row < n&& pt.col >= 0 && pt.col < m&& a[pt.row][pt.col] == 0){return true;}else {return false;}
}//这里只需要一条路,直接返回bool值
bool dfs(int** a, int n, int m, PT pt)
{st.push(pt);if (pt.row == n - 1 && pt.col == m - 1){//找到出口return true;}a[pt.row][pt.col] = 2;//开始遍历四个方向//上PT next = pt;next.row -= 1;if (isPath(a, n, m, next)){if (dfs(a, n, m, next)){return true;}}//右next.row += 1;next.col += 1;if (isPath(a, n, m, next)){if (dfs(a, n, m, next)){return true;}}//下next.col -= 1;next.row += 1;if (isPath(a, n, m, next)){if (dfs(a, n, m, next)){return true;}}//左next.row -= 1;next.col -= 1;if (isPath(a, n, m, next)){if (dfs(a, n, m, next)){return true;}}st.pop();//四个方向都不行,则false;return false;
}void Print(stack<PT> st)
{stack<PT> rt;while (!st.empty()){rt.push(st.top());st.pop();}while (!rt.empty()){cout << "(" << rt.top().row << "," << rt.top().col << ")" << endl;rt.pop();}
}int main() {int n, m;while (cin >> n >> m) { // 注意 while 处理多个 case//开辟一个动态二维数组int** tmp = (int**)malloc(sizeof(int*) * n);for (int i = 0; i < n; ++i){tmp[i] = (int*)malloc(sizeof(int) * m);}for (int i = 0; i < n; ++i){for (int j = 0; j < m; ++j){cin >> tmp[i][j];}}//定义结构体PT pt;pt.row = 0;pt.col = 0;bool flag = dfs(tmp, n, m, pt);if (flag == true){Print(st);}}}

迷宫问题返回最短路径

描述
小青蛙有一天不小心落入了一个地下迷宫,小青蛙希望用自己仅剩的体力值P跳出这个地下迷宫。为了让问题简单,假设这是一个n*m的格子迷宫,迷宫每个位置为0或者1,0代表这个位置有障碍物,小青蛙达到不了这个位置;1代表小青蛙可以达到的位置。小青蛙初始在(0,0)位置,地下迷宫的出口在(0,m-1)(保证这两个位置都是1,并且保证一定有起点到终点可达的路径),小青蛙在迷宫中水平移动一个单位距离需要消耗1点体力值,向上爬一个单位距离需要消耗3个单位的体力值,向下移动不消耗体力值,当小青蛙的体力值等于0的时候还没有到达出口,小青蛙将无法逃离迷宫。现在需要你帮助小青蛙计算出能否用仅剩的体力值跳出迷宫(即达到(0,m-1)位置)。
输入描述:
输入包括n+1行:
第一行为三个整数n,m(3 <= m,n <= 10),P(1 <= P <= 100)
接下来的n行:
每行m个0或者1,以空格分隔
输出描述:
如果能逃离迷宫,则输出一行体力消耗最小的路径,输出格式见样例所示;如果不能逃离迷宫,则输出"Can not escape!"。 测试数据保证答案唯一
输入4 4 10 1 0 0 1 1 1 0 1 0 1 1 1 0 0 1 1
[0,0],[1,0],[1,1],[2,1],[2,2],[2,3],[1,3],[0,3]

这里的思想同上面类似。

  但是也有略微区别,这里要求最短路径,我们怎么知道求出的答案就是最短的路劲呢?所以这里要遍历所有可以前进的路线。走的路径进行标记,不走的路劲标记过的要取消标记。

源代码

#include <iostream>
using namespace std;
#include<stack>//定义坐标typedef struct pt {int row;int col;
}PT;//普通路径
stack<PT> st;
//最短路径
stack<PT> minSt;//判断能否通过
bool isPath(int** tmp, int n, int m, PT pt)
{if (pt.row >= 0 && pt.row < n&& pt.col >= 0 && pt.col < m&& tmp[pt.row][pt.col] == 1){return true;}else {return false;}
}//这里我们要找到·所有路径,所以不用返回
void dfs(int** tmp, int n, int m, PT pt, int p)
{//每次进来先入栈st.push(pt);//走过的路标记为2tmp[pt.row][pt.col] = 2;if (p >= 0 && pt.row == 0 && pt.col == m - 1){//更新最短路径if (st.size() < minSt.size() ||minSt.empty()){minSt = st;}}//枚举所有方法PT next;//上next = pt;next.row -= 1;if (isPath(tmp, n, m, next)){dfs(tmp, n, m, next, p - 3);}//右next = pt;next.col += 1;if (isPath(tmp, n, m, next)){dfs(tmp, n, m, next, p - 1);}//下next = pt;next.row += 1;if (isPath(tmp, n, m, next)){dfs(tmp, n, m, next, p);}//左next = pt;next.col -= 1;if (isPath(tmp, n, m, next)){dfs(tmp, n, m, next, p - 1);}//都不能走,还原路径为1tmp[pt.row][pt.col] = 1;st.pop();//四个方向都不能走
}//进行对栈的打印
void Print(stack<PT> st)
{stack<PT> rt;while (!st.empty()){rt.push(st.top());st.pop();}while (rt.size() > 1){cout << "[" << rt.top().row << "," << rt.top().col << "]" << ",";rt.pop();}cout << "[" << rt.top().row << "," << rt.top().col << "]" << endl;rt.pop();
}int main() {int n, m, p;while (cin >> n >> m) { // 注意 while 处理多个 casecin >> p;//开辟二维数组int** tmp = (int**)malloc(sizeof(int*) * n);for (int i = 0; i < n; ++i){tmp[i] = (int*)malloc(sizeof(int) * m);}//输入for (int i = 0; i < n; ++i){for (int j = 0; j < m; ++j){cin >> tmp[i][j];}}PT pt;pt.row = 0;pt.col = 0;dfs(tmp, n, m, pt, p);if (!minSt.empty()){Print(minSt);}else {cout << "Can not escape!" << endl;}}
}

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

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

相关文章

Linux的UDEV机制

udev 机制引入&#xff1a; 手机接入Linux热拔插相关 a. 把手机接入开发板 b. 安装adb工具&#xff0c;在终端输入adb安装指令&#xff1a; sudo apt-get install adb c. dmeg能查看到手机接入的信息&#xff0c;但是输入adb devices会出现提醒 dinsufficient permissions for …

NTLM认证

文章目录 1.概念(1) 本地认证(2) SAM(3) NTLM Hash(4) NTLM 和 NTLM Hash(5) NTLM v2 1.概念 (1) 本地认证 Windows不存储用户的明文密码&#xff0c;它会将用户的明文密码经过加密后存储在 SAM (Security Account Manager Database&#xff0c;安全账号管理数据库)中。 (2)…

【UnityShader】图片圆角

1.需求 我们在开发的时候&#xff0c;有时候一些按钮或者菜单栏的边角是直角的需要改成圆角&#xff0c;但是让美术重新绘制耽误时间不说也确实没必要&#xff0c;这个时候我们不妨使用一个简单的shader去解决这个问题&#xff0c;下面我们就讲讲这个shader要如何实现。 需求1…

[阅读笔记15][Orca]Progressive Learning from Complex Explanation Traces of GPT-4

接下来是微软的Orca这篇论文&#xff0c;23年6月挂到了arxiv上。 目前利用大模型输出来训练小模型的研究都是在模仿&#xff0c;它们倾向于学习大模型的风格而不是它们的推理过程&#xff0c;这导致这些小模型的质量不高。Orca是一个有13B参数的小模型&#xff0c;它可以学习到…

【BUG】Hexo|GET _MG_0001.JPG 404 (Not Found),hexo博客搭建过程图片路径正确却找不到图片

我的问题 我查了好多资料&#xff0c;结果原因是图片名称开头是_则该文件会被忽略。。。我注意到网上并没有提到这个问题&#xff0c;遂补了一下这篇博客并且汇总了我找到的所有解决办法。 具体检查方式&#xff1a; hexo生成一下静态资源&#xff1a; hexo g会发现这张图片…

本地消息表模式保障分布式系统最终一致性

系统架构说明 状态转换说明 订单表消息表process_queue库存系统return_queue说明成功失败///订单库回滚成功成功失败//订单系统重发消息成功成功成功失败/Broker自动重试&#xff0c;注意接口幂等成功成功成功库存不足退回/Broker通知回掉&#xff0c;订单/消息作废成功成功成…

回溯算法练习day.4

93.复原ip地址 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"…

Kafka导航【Kafka】

Kafka导航【Kafka】 前言版权推荐Kafka随堂笔记 第三章 生产者3.4生产者分区3.4.1.分区好处3.4.2 生产者发送消息的分区策略3.4.3 自定义分区器 3.5 生产经验——生产者如何提高吞吐量3.6 生产经验——数据可靠性3.7 生产经验——数据去重3.7.1 数据传递语义3.7.2 幂等性3.7.3生…

虚拟机扩容方法

概述 我的虚拟机开始的内存是40G,接下来要扩成60GB 扩容步骤 步骤1 步骤2 步骤3 修改扩容后的磁盘大小&#xff0c;修改后的值只可以比原来的大&#xff0c;修改完成后点击扩展&#xff0c;等待扩展完成 步骤4 虽然外面扩展成功&#xff0c;但是新增的磁盘空间虚拟机内部还…

C++:类与对象完结篇

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;运算符重载》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 文章目录 重新认识构造函数1.初始化列表2.explicit关键字 static成员1.sta…

密码学 | 承诺:常见的承诺方案

&#x1f951;原文&#xff1a;密码学原语如何应用&#xff1f;解析密码学承诺的妙用 - 知乎 1 简介 密码学承诺 涉及 承诺方、验证方 两个参与方&#xff0c;以及以下两个阶段&#xff1a; 承诺阶段&#xff1a;承诺方选择一个敏感数据 v v v&#xff0c;为它计算出相应…

Adobe Acrobat DC 2022:全方位PDF编辑利器,解锁文档处理新境界

在当今信息爆炸的时代&#xff0c;PDF格式因其跨平台性、稳定性以及易读性而备受欢迎&#xff0c;成为办公、学习和交流的常用格式。Adobe Acrobat DC 2022作为专业的PDF编辑软件&#xff0c;凭借其卓越的性能和丰富的功能&#xff0c;赢得了众多用户的青睐。 Adobe Acrobat D…