【深度优先搜索算法】与【宽度优先搜索算法】
深度优先搜索算法
深度优先搜索算法(Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。
深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。
算法实现:
利用函数栈来保存当前搜索路径中每个节点的状态,每搜索一个新节点,就标记此节点被使用并递归调用一次dfs函数,确定此节点在本路径中无法到达终点,则return上一级函数,更换下一节点。
注意问题:
1、回溯后是否要将节点标记重置应该看路径来源是否会对节点能否到达出口产生影响,如果任意路径到达此节点都不会影响它能否到达终点,则不去除标记,因为即使下一次搜索到它,也知道它无法到达终点,从而跳过它。
如果不同路径来源会影响,则需要重置标记,保证能被其他路径再次选取。
2、剪枝,通过对题目的理解,在选取节点递归之前,直接判断此节点能否到达终点,从而减少大量不必要的搜索过程。
扩展:点击打开链接
Eg:
POJ2386:有一个大小为N*M的园子,雨后积起了水。八连通的积水被认为是连接在一起的。请求出园子里总共有多少水洼?
***
*W*
***
/*从任意的W开始,不停地把邻接的部分用“。”代替。1次dfs后与初始的这个W连接的所有W就被替换成了“。”,因此直到图中不再 *存在W为止,总共进行DFS的次数就是答案了。8个方向共对应了8种状态转移,每个格子作为DFS的参数至多被调用一次,所以复杂度为O(N*M)
*/ int N, M;
char field[MAX_N][MAX_N + 1]; //现在位置(x, y)
void dfs(int x, int y) { //将现在所在位置替换为. field[x][y] = '.'; //循环遍历移动的8个方向 for (int dx = -1; dx <=1; dx ++ ) { for (int dy = -1; dy <= 1; dy ++) { // 向x方向移动dx,向y方向移动dy,移动的结果是(nx, ny) int nx = x + dx, ny = y + dy; //判断(nx,ny)是不是在园子内,以及是否有积水 if (0<=nx && nx < N && ny>=0 && ny<M && field[nx][ny] == 'W') dfs(nx, ny); } } return ;
} void solve() { int res = 0; for (int i = 0; i<N; i++) { for (int j = 0; j<M; j++) { if (field[i][j] == 'W') { //从有W的地方开始dfs dfs(i, j); res ++ ; } } } cout << res << endl;
}
广度优先搜索算法
深度优先搜索(隐式的)利用了栈进行计算,而宽度优先搜索则利用了队列。搜索时首先将初始状态加到队列里,此后队列的最前端不断取出状态,把从该状态可以转移到的状态中尚未访问过的部分加入队列,
如此反复,直至队列被取空或找到了问题的解。通过观察这个队列,我们可以知道所有的状态都是按照距离初始状态由近及远的顺序遍历的。
输入:'#','.','S','G'分别表示墙壁、通道、起点、终点
宽度优先搜搜按照距开始状态由近及远的顺序进行搜索,因此可以很容易的用来求最短路径、最少操作之类问题的答案。这个问题中,状态仅仅是目前所在位置的坐标,因此可以构成pair或者编码成int来表达状态。当状态更加复杂时,就需要封装成一个类来表示状态了。转移的方式为四方向移动,状态数与迷宫的大小是相等的,所以复杂度是O(4*N*M) = O(N*M)。
宽度优先搜索中,只需要将已经访问过的状态用标记管理起来,就可以很好地做到由近及远的搜索。这个问题中由于要求最短距离,不妨用d[N][M]数组把最短距离保存起来。初始时用充分大的常数INF来初始化它,这样尚未到达的位置就是INF,也就同时起到了标记的作用。
虽然到达终点时候就会停止搜索,可如果继续下去直到队列为空的话,就可以计算出到各个位置的最短距离。此外,如果搜索到最后,d仍然为INF的话,便可得知这个位置就是无法从起点到达的位置。
const int INF = 100000000; //使用pair表示状态时,使用typedef会更加方便一些
typedef pair <int, int> P; char maze[MAX_N][MAX_M+1]; //表示迷宫的字符串数组
int N, M;
int sx, sy; //起点坐标
int gx, gy; //终点坐标 int d[MAX_N][MAX_M]; //到达各个位置的最短距离的数组 //4个方向移动的向量
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1}; //求从{sx, sy} 到{gx, gy}的最短距离
//如果无法到达,则是INF
int bfs() { queue<p> que; //把所有的位置都初始化INF for (int i = 0; i<N; i++) for (int j = 0; j<M; j++) d[i][j] = INF; //将起点加入队列,并把这一地点的距离设置为0 que.push(P(sx, xy)); d[sx][xy] = 0; //不断循环直到队列的长度为0 while (que.size()) { //从队列的最前端取出元素 P p = que.front(); que.pop(); //如果取出的状态已经是终点,则结束搜索 if (p.first == gx && p.second == gy) break; //四个方向的循环 for (int i = 0; i<4; i++) { //移动之后的位置记为(nx, ny) int nx = p.first + dx[i], ny = p.second + dy[i]; //判断是否可以移动以及是否已经访问过(d[nx][ny] != INF即为已经访问过) if (0 <= nx && nx < N && 0 <= ny && ny < M && maze[nx][ny] != '#' && d[nx][ny] == INF) { //可以移动的话,则加入到队列,并且到该位置的距离确定为到p的距离加1 que.push(P(nx, ny)); d[nx][ny] = d[p.first][p.second] + 1; } } } return d[gx][gy];
} void solve() { int res = bfs(); cout << res << endl;
}
【深度优先搜索算法】与【宽度优先搜索算法】相关推荐
- 算法导论:dfs深度优先搜索算法及基于dfs的拓扑排序以及宽度优先搜索算法bfs
1.dfs深度优先搜索算法 算法导论中是通过三种标记颜色来介绍dfs的,white代表还没被搜过,grey代表被搜了一些,还没结束,white表示已经搜索完成的状态. c/c++复现dfs代码 #in ...
- BFS广度优先搜索算法//宽度优先搜索算法
BFS宽度优先搜索算法,又称广度优先搜索,是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型. Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想. ...
- 宽度优先搜索算法(BFS)详解(超级详细讲解,附有大图)
目录 一.宽度优先搜索(BFS)是什么? 二.图解宽搜(BFS) 三.对比与发现 四.工具--队列 五.模板 六.最后 一.宽度优先搜索(BFS)是什么? 百度百科这样说: 宽度优先搜索算法(又称广度 ...
- 宽度优先搜索算法解决八数码问题
宽度优先搜索算法解决八数码问题 原理 1.宽度优先搜索是指在一个搜索树中,搜索以同层邻近节点依次扩展节点.这种搜索是逐层进行的,在对下一层的任一节点进行搜索之前,必须搜索完本层的所有节点. 宽度优先搜 ...
- 深度优先搜索和宽度优先搜索
深度优先搜索和宽度优先搜索 bfs和dfs都是遍历图的方法.dfs是不撞南墙不回头,bfs慢慢来,一层一层来. 类型 空间(h为高度) 时间(h为高度) 采用的数据结构 特点 DFS O(h) O( ...
- ACM算法笔记(十)深度优先搜索与宽度优先搜索
深度优先搜索 事实上,深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次. 下面 ...
- 数据结构与算法—图论之dfs、bfs(深度优先搜索、宽度优先搜索)
文章目录 前言 邻接矩阵和邻接表 深度优先搜索(dfs) 宽度(广度)优先搜索(bfs) 总结与比较 前言 在有向图和无向图中,如果节点之间无权值或者权值相等,那么dfs和bfs时常出现在日常算法中. ...
- 深度优先搜索与宽度优先搜索
深度优先搜索 简称:DFS 基本思路 深度优先遍历图的方法是,从图中某顶点v出发: (1)访问顶点v: (2)依次从v的未被访问的邻接点出发,对图进行深度优先遍历:直至图中和v有路径相通的顶点都被访问 ...
- 图的深度优先遍历和宽度优先遍历C语言,图的广度、深度优先遍历 C语言
以下是老师作为数据结构课的作业的要求,没有什么实际用处和可以探讨和总结的的地方,所以简单代码直接展示. 宽度优先遍历: #include #include #include using namespa ...
最新文章
- 全局性业务架构建模工作步骤
- 轻松理解正向代理与反向代理
- mysql1215_这15条MySQL改善经验必须收藏
- 《Photoshop Lab修色圣典(修订版)》—第1课深入讨论
- React 中的父子组件 兄弟组件传值
- nacos linux启动_微服务系列之Nacos配置中心之一:Nacos介绍与安装
- 提升对前端的认知,不得不了解Web API的DOM和BOM
- 细数判断数据类型的各种方法
- diablo2oo2’s Universal Patcher 中文汉化绿色破解版下载
- kali2020 中文乱码问题
- 【电脑突然识别不了外置光驱】
- yolov5样本处理方式
- 深度学习论文写作框架
- fadeIn fadeOut
- 线上云酒馆是什么?线上云酒馆怎么开发?
- PTW International宣布运营电竞战队“Orange Rock Esports”
- 老牌好用免费的数据恢复软件easyrecovery操作简单一键恢复
- php网页全屏背景图代码,HTML5 body设置全屏背景图片的示例代码
- Android 基础知识4-2.11 AbsoluteLayout(绝对布局)详解
- android 开发常用apk工具
热门文章
- github:master提交项目到远程仓库出现“There isn’t anything to compare.”
- 个人图床的最简单制作-腾讯云COS
- ubuntu安装zlib
- C语言——经典200道实例【基础例题100道——进阶例题100道】
- 蓝桥杯少儿编程2020年8月份C++比赛每日一练
- 2022广东省+深圳市+11个区“专精特新”及小巨人企业补贴政策
- 注册中心对比Zookeeper、Eureka、Nacos、Consul和Etcd
- 推荐几个财富自由大佬的公众号
- modbus虚拟服务器,modbus客户端服务器区别
- mbr linux安装分区格式,装机、做系统必备:秒懂MBR和GPT分区表