DFS and BFS

一. DFS的基本概念

深度优先搜索(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当搜索遇到阻碍,如节点 的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点 的那条边的起始节点,换条路接着搜。
注意可以将dfs理解为栈,将各个子节点当作一个个的栈,然后将每个栈都遍历出来

问题示例

1.树或图的遍历问题

遍历无根树

#include<iostream>
#include<vector>using namespace std;
const int N = 5e5+10;
int n,s;
vector<int> tre[N];//利用vector邻接链表来存树,表示与N相连接的点
void dfs(int u,int p)//u为子节点,p为父节点
{cout << u << endl;for(int i = 0;i < tre[u].size();i ++)//dev c++中不能使用for(int v;tre[u])来遍历vector容器(c++11特性){if(tre[u][i]!=p) dfs(tre[u][i],u);}
}
int main()
{cin >> n >> s;for(int i = 1,u,v;i < n;i ++){cin >> u >> v;tre[u].push_back(v);tre[v].push_back(u);}dfs(s,0);//s为起点return 0;
}

遍历图

#include<iostream>
#include<vector>
using namespace std;
const int N = 5e6+10;
int n,m,s;
int vis[N];
vector<int> gra[N];
void dfs(int s)
{cout << s << endl;vis[s] = 1;//标记已经搜过的节点 for(int i = 0;i < gra[u].size();i ++)//在c++11中可以使用for(int v,tra[u])来遍历vector容器 {if(!vis[gra[u][i]]) dfs(gra[u][i]);//只搜没被标记的节点 }
}
int main()
{cin >> n >> m >>s;for(int i = 1,v,u;i <= n;i ++){cin >> v >> u;gra[u].push_back(v);gra[v].push_back(u);}
}

时间复杂度:O(n)

2.暴力搜索问题

题目链接:https://www.luogu.com.cn/problem/P1605
题目描述:给定一个 方格的迷宫,迷宫里有 处障碍,障碍处不可通过。给定起点坐标和终
点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫中移动有上下左右
四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
数据范围:1<= n,m <=5
样例输入:

2 2 1
1 1 2 2
1 2

样例输出:

1

思路:暴力硬搜。我们用DFS的搜索策略,一条道走到黑,从起始点搜索出所有到终点的路径。在搜索的过程中遇到边界、障碍物和走过的点就返回,否则就接着搜下去,如果一个点无法继续走下去了,就回到上一个节点,同时把本节点的标记请0,换条路接着搜。

#include<iostream>
using namespace std;
int vis[10][10];//判断是否为障碍物,走过的点
int sx,sy,fx,fy,n,m,k;
int dx[] = {-1,1,0,0};//方向数组  对应上下左右
int dy[] = {0,0,-1,1};//方向数组  对应上下左右
int cnt;
void dfs(int x,int y)
{if(x<1||y<1||x>n||y>m||vis[x][y]) return;//障碍物、被标记的点 ,边界都要返回 if(x==fx&&y==fy){cnt++;return;}vis[x][y] = 1;for(int i = 0;i < 4;i ++) dfs(dx[i]+x,dy[i]+y);vis[x][y] = 0;//无路可走了,往上回溯,这点我不走了,标记为回0
}int main()
{cin >> n >> m >> k;cin >> sx >> sy >> fx >> fy;for(int i = 0;i < k;i ++) {int x,y;cin >> x >> y;vis[x][y] = 1;}dfs(sx,sy);cout << cnt << " ";return 0;}

3.联通块问题

题目链接:http://poj.org/problem?id=1562
题目大意:给你一个 的格子,格子中只包含 * 和 @ ,相邻的 @ 被视为同一块(周围八个方向的
格子都视为相邻,问你格子中一共有多少块 @。
数据范围:多组输入,1<= n,m <=100

1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
0 0

样例输出:

0
1
2
2

思路:我们从每个未被访问过的 @ 出发,搜索它的八个方向上相邻的点,把 * 当成墙,遇到 * 就返回不搜了,遇到 @ 如果没被搜过就当成始点接着搜,搜完@后要标记,这样调用dfs的次数就是连通块的个数。因为每调用一次dfs就消除了一个连通块。
时间复杂度:O(n*m)

#include<iostream>
using namespace std;
char s[110][110];
int n,m;
int dx[]= {-1,-1,-1,0,0,1,1,1};//两个方向数组反别对应左上 上 右上 左 右 左下 下 右下
int dy[]= {-1,0,1,-1,1,-1,0,1};
int vis[110][110];//查询@是否被搜过
void dfs(int x,int y)
{if(x<1||y<1||x>n||y>m||vis[x][y]||s[x][y]=='*') return ;//如果@已经被搜过了就返回vis[x][y] = 1;for(int i = 0;i < 8;i ++) dfs(dx[i]+x,dy[i]+y);
}
int main()
{while(cin >> n >> m && n && m){for(int i = 1;i <= n; i ++){for(int j = 1;j <= m;j ++) {cin >> s[i][j];vis[i][j] = 0;//多组输入要初始化}}int ans = 0;for(int i = 1;i <= n;i ++){for(int j = 1;j <= m;j ++){if(!vis[i][j]&&s[i][j]=='@')//@必须为没被遍历过{dfs(i,j);ans++;}}}cout << ans << endl;}return 0;
}

其中

for(int i = 1;i <= n; i ++){for(int j = 1;j <= m;j ++) {cin >> s[i][j];vis[i][j] = 0;//多组输入要初始化}

也可以写成

for(int i = 1;i <= n;i ++) cin >> s[i]+1;//s[i]是个二维字符数组,也可以当成一维字符串来处理 其中+1是为了保证下标从1开始,s[i]相当于指针for(int i = 1;i <= n; i ++){for(int j = 1;j <= m;j ++) {vis[i][j] = 0;}}

如果使用字符串的话下标只能从0开始,使用字符数组可以使下标从1开始,而且指针要加1即s[i]+1。

二.BFS基本概念

广度优先搜索(Breadth First Search,简称 BFS)从一个点出发,扩散到周围的点,按照层次优先的原则搜索完所有的点。形象点描述就像将一块石头扔到池塘里,石头所激发出的波纹传播到整个池塘的过程。
注意可以将其看作队列,遵守先进先出的原则
代码实现:

#include<iostream>
#include<queue>
using namespace std;
const int N = 5e6+10;
int n,m,s;
int vis[N];
vector<int> gra[N];
void bfs(int s)
{queue<int> que;que.push(s);vis[s] = 1;while(!que.empty()){int u = que.front();que.pop();cout << u << endl;for(int i = 0;i < gra[s].size();i ++){if(!vis[gra[s][i]]) continue;//入过队就不再搜了 que.push(gra[s][i]);vis[gra[s][i]] = 1;//入队后打上标记 }}
}
int main()
{cin >> n >> m >> s;for(int i = 0,u,v;i < n;i ++){cin >> u >> v;gra[u].push_back(v);gra[v].push_back(u);}return 0;
}

问题示例

最短路

BFS的主要用途就是在边权为1的图上求最短路。当边权不为1时要用到floyd
例题:逃离迷宫
题目链接:https://ac.nowcoder.com/acm/contest/96/G?&headNav=www
题目大意:给你一个 的格子,格子中 ‘.’ 可以走 ,’#’ 不可以走,‘P’ 代表人物位置,‘K’ 代表钥匙(钥匙可以有多把),‘E’ 代表出口。每次可以花一单位时间向周围四个方向(上,下,左,右)走一格。逃出迷宫需要拿到钥匙到达出口,没有钥匙就无法通过出口,问你最少多久可以逃出迷宫,如果无法逃出则输出 “No solution”。
数据范围:多组数据 T 1 <= T <= 50 1 <= n,m <= 500
样例输入:

3
5 5
....P
##..E
K#...
##...
.....
5 5
P....
.....
..E..
.....
....K
5 5
P#..E
.#.#.
.#.#.
.#.#.
...#K

样例输出:

No solution
12
No solution

思路:由于bfs是广度搜索,本质是逐层便历,当某节点被第一次搜到时,这个距离便是它与起点的最短距离,对于此题我们首先要拿到钥匙,然后再从钥匙处走到出口,因此我们可以求出两段距离,一段是起点与钥匙的距离,另一段是钥匙与出口的距离(钥匙可以有多把),利用bfs可求出起点与所有点的最短距离,由于bfs是单源最短路,只能求一个点到多个点的最短距离,所以当求第二段距离时,可以求出口到各个钥匙的最短距离(逆向思维),可能会有多条道路,遍历出每把钥匙的位置,然后找出所有可能的道路,最后找出距离最小的道路,如果没有解,则输出No solution。

#include<iostream>
#include<queue>
using namespace std;
const int N = 150;
const int INF = 0x3f3f3f3f;
struct Node{int x,y,w;//w为起点到该点的距离
};
char s[N][N];
int dis[2][N][N];//0与1分别表示两段不同的距离,0表示起点到钥匙,1表示钥匙到出口
int dx[] = {-1,1,0,0};
int dy[] = {0,0,-1,1};
int t,n,m;
queue<Node> que;
void bfs(int k,int x,int y)
{for(int i = 1;i <= n;i ++){for(int j = 1;j <= m;j ++) dis[k][i][j] = INF;//表示不能到达该点}que.push({x,y,0});while(!que.empty()){Node t = que.front();que.pop();for(int i = 0;i < 4;i ++){int x = t.x+dx[i],y = t.y+dy[i];if(x<1||y<1||x>n||y>m||s[x][y]=='#'||s[x][y]=='E'||dis[k][x][y]!=INF) continue;//s[x][y]=='E',这个条件容易被忽略,在求第1段距离时不能穿过'E'que.push({x,y,t.w+1});dis[k][x][y] = t.w+1; }}}
int main()
{cin >> t;while(t--){cin >> n >> m;for(int i = 1;i <= n;i ++) cin >> s[i]+1;for(int i = 1;i <= n;i ++){for(int j = 1;j <= m;j ++){if(s[i][j]=='P') bfs(0,i,j);if(s[i][j]=='E') bfs(1,i,j); }}int ans = INF+INF;for(int i = 1;i <= n;i ++)//枚举所有的钥匙点{for(int j = 1;j <= m;j ++){if(s[i][j]=='K') ans = min(ans,dis[0][i][j]+dis[1][i][j]);//可能会有多个解,找出最小的} }if(ans>=INF) cout << "No solution\n";else cout << ans << endl;}
}

DFS and BFS相关推荐

  1. 数据结构基础(21) --DFS与BFS

    DFS 从图中某个顶点V0 出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相通的顶点都被访问到(使用堆栈). //使用邻接矩阵存储的无向图的深度 ...

  2. LeetCode算法题7:DFS和BFS

    文章目录 前言 深度优先搜索算法伪代码: 广度优先搜索算法伪代码: 一.图像渲染 DFS: BFS: 上面BFS算法存在的问题: 修改 1: 修改 2: 二.岛屿的最大面积 DFS: BFS : 三. ...

  3. 连通图的判断(并查集, DFS, BFS)

    首先要明确什么是连通图??? 连通图:对于一个图来说,图中的任意一个点都能访问到所有的点,则说明该图连通 很明显,如果要判断一个图是否连通,则必须要从任意一个搜索一遍,判断是否到达了所有的点,则很快会 ...

  4. PAT甲级1099 Build A Binary Search Tree (30分):[C++题解]建立二叉搜索树、dfs和bfs

    文章目录 题目分析 题目链接 题目分析 题意重述:给定一棵二叉树的结构,和待填的数值,请将数据填到二叉树中的结点中,使之满足二叉搜索树的性质. 然后按照层序遍历输出数值. 分析: 本题分两步. 第一步 ...

  5. python 拓扑排序 dfs bfs_拓扑排序的DFS和BFS

    博主以前有一个疑问,DFS和BFS各自的适用范围是?我想你今天看了这篇文章之后会有一个判断! BFS 数据结构与算法分析:c语言描述(p217) 已经存在一个Indgree入度数组(indgree[v ...

  6. 一文搞懂深度优先搜索、广度优先搜索(dfs、bfs)

    前言 你问一个人听过哪些算法,那么深度优先搜索(dfs)和宽度优先搜索(bfs)那肯定在其中,很多小老弟学会dfs和bfs就觉得好像懂算法了,无所不能,确实如此,学会dfs和bfs暴力搜索枚举确实利用 ...

  7. 数据结构与算法—图论之dfs、bfs(深度优先搜索、宽度优先搜索)

    文章目录 前言 邻接矩阵和邻接表 深度优先搜索(dfs) 宽度(广度)优先搜索(bfs) 总结与比较 前言 在有向图和无向图中,如果节点之间无权值或者权值相等,那么dfs和bfs时常出现在日常算法中. ...

  8. dfs时间复杂度_吊打DFS和BFS,什么情况下可以用二分?

    LintCode 600 包裹黑色像素点的最小矩形 题目描述 一个由二进制矩阵表示的图,0 表示白色像素点,1 表示黑色像素点.黑色像素点是联通的,即只有一块黑色区域.像素是水平和竖直连接的,给一个黑 ...

  9. 列出连通集 (25 分)【DFS与BFS模板】

    立志用最少的代码做最高效的表达 给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集.假设顶点从0到N−1编号.进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访 ...

  10. (最优解法)46行代码AC_HDU1242 Rescue(DFS解法+BFS解法)

    励志用少的代码做高效表达 Problem Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. T ...

最新文章

  1. JavaScript实现使用DisjointSet 检测无向循环算法(附完整源码)
  2. python全栈开发学习 01
  3. Linux 服务器程序规范、服务器日志、用户、进程间的关系
  4. 有人不会使用计算机的反义,现代汉语练习题及答案
  5. vue-cli本地的一个websocket
  6. 弹性地基梁计算程序 注册机_详解抗滑桩类型、设计及计算方法
  7. C++ vector用法总结
  8. 深度学习实践指南(六)—— ReLU(前向和后向过程)
  9. VBB 3.8.4 XSS
  10. DDR4、LPDDR4、LPDDR4x区别及DDR拓展
  11. 这个季节有离别——观《Sad Movie》有感
  12. 三种方法,让WPF项目生成单文件
  13. Android4.1
  14. Java 简易五子棋游戏的编写
  15. [笔记]OpenCV+FFmpeg+Qt实现视频编辑器之OpenCV视频lO接口
  16. 计算机启动盘安装教程,小白装机u盘使用方法
  17. 人生就是一个不断学习的过程
  18. 深入浅出XDL(四):模型训练
  19. CKEditor的使用示例
  20. Pycharm永久激活七步走

热门文章

  1. 福昕阅读器给pdf创建目录方法
  2. 基于FBX SDK的FBX模型解析与加载 -(三)
  3. 根据汉字获取它的字符串拼音首字母(大写),含多音字
  4. 面向对象的3个基本对象
  5. 基尼系数,省级层面、地级市层面、Dagum1997方法,整理好的面板数据
  6. freenom又行了-免费顶级域名白嫖一年,赶紧看看如何申请
  7. 初入Java,安装jdk,ij编译,运行
  8. 验证码识别PaddleOCR 快速开始
  9. Python报错ModuleNotFoundError: No module named ‘concurrent‘
  10. bat 脚本修改IE浏览器代理服务器