-
2022-03-18 19:36:11
注:上次写了一个宽度优先的,代码组织得不好,不能很好体现宽度优先的算法思路。 今天重修整理了一版新的。
3×3九宫棋盘,放置数码为1-8的8个棋牌,剩下一个空格,只能通过棋牌向空格的移动来改变棋盘的布局。
要求:根据给定的初始状态和目标状态,空格只能上下左右4个方向移动,一次只能移动一个格子,如何才能从初始状态到达目标状态,找到合法的走步序列。
''' 宽度优先算法求解八数码问题; ''' import numpy as np class State: ''' 状态图 ''' def __init__(self, state, directionFlag=None, parent=None): self.state = state # 当前状态 self.depth = parent.depth + 1 if parent is not None else 0 self.direction = ['up', 'down', 'right', 'left'] # 操作符 , 顺序即操作符运算顺序; if directionFlag: # 被禁止的操作符(如果使用该操作符,会回到父亲节点,导致
更多相关内容 -
C++实现广度优先搜索实例
2021-01-01 03:23:38本文主要叙述了图的遍历算法中的广度优先搜索(Breadth-First-Search)算法,是非常经典的算法,可供C++程序员参考借鉴之用。具体如下: 首先,图的遍历是指从图中的某一个顶点出发,按照某种搜索方法沿着图中的边... -
广度优先搜索
2021-05-23 10:02:49宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于...一、概述
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
二、广度优先搜索步骤
广度优先搜索使用队列(queue)来实现,过程如下
1、把根节点放到队列的末尾。
2、每次从队列的头部取出一个元素并弹出,查看这个元素所有的下一级元素,把它们放到队列的末尾。
3、找到所要找的元素时结束程序。
4、如果遍历整个树还没有找到,结束程序。
三、代码
下面实现对一个用邻接矩阵存储的图进行广度优先搜索。
#include<iostream> #include<queue> using namespace std; //遍历顺序 const int N=7; int matrix[][N]={ {0,1,1,0
-
C++ 广度优先搜索
2020-11-18 17:47:33广度优先搜索和一条路走到底走不通再回头的深度优先搜索不同的是,他按层进行搜索的,会按照设定好的方向例如[右, 上, 左, 下]的逆时针方向,先将四个方向的下一个点能走的全部放进一个队列种,然后按照队列的...广度优先搜索和一条路走到底走不通再回头的深度优先搜索不同的是,他按层进行搜索的,会按照设定好的方向例如[右, 上, 左, 下]的逆时针方向,先将四个方向的下一个点能走的全部放进一个队列种,然后按照队列的顺序依次走下一层,所以广度有点搜索不仅可以判断连通性的问题还可以判断到达终点需要的步数;
同样以迷宫
S. . .
##. .
##. .
T. . .为例子来进行广度优先搜索:
首先由于需要用到队列所以需要队列的头文件,依然是字符地图,方向数组以及地图大小和起始点,这里为了判断需要的步数所以定义了一个结构体包括当前位置(x,y)以及到当前位置用了几步。
首先输入地图以及确定起始点。
建立一个队列que,将起始点入栈,起始点的步数为0,之后若队列不为空的话,就是可以继续遍历,按照方向数组得到下一个点的位置(xx,yy)假如新的点是终点T的话直接输出当前节点+1的步数因为判断的是下一个点才是终点,假如是路‘ . ’的话就将该点进栈,并且该点的步数为栈首(也就是上一个点)的步数+1,假如队列空了还没有返回值的话,也就意味这没有能够到达。
最后看下结果:
最后输出了达到的步数为7
-
广度优先搜索和深度优先搜索
2021-11-22 09:59:27广度优先搜索算法框架1)单源广度优先搜索2)多源广度优先搜索3)双向广度优先搜索 1. 前言 深度优先搜索算法的基础是递归,如果你对递归还不熟悉的话,建议先去看看递归的概念,做一些递归的练习题,也...文章目录
1. 前言
深度优先搜索算法的基础是递归,如果你对递归还不熟悉的话,建议先去看看递归的概念,做一些递归的练习题,也可以看我之前写的递归的文章:递归算法详解
2. 广度优先搜索和深度优先搜索
在这篇文章中同时总结下广度优先搜索和深度优先搜索,这两种算法是针对 “图” 的遍历方法,当然这里的图是指的是广义上的图,可以是实际的图,可以是N叉树,甚至可以是二维矩阵。其中深度优先搜索是每一次按照一个方向进行穷尽式的搜索,当该方向上的搜索无法继续往前的时候,这时就退回到上一步,换一个方向继续搜索。而广度优先走是按照层次由近及远的进行搜索,在当前层次所有可及节点都搜索完毕后才会继续往下搜索,其本质就是寻找从起点到终点的最短路径。下面以二叉树的遍历过程说明两种搜索算法之间的区别:
1)深度优先搜索
这种搜索方法会按照一个方向进行穷尽搜索,所以首先会一直搜索左子树,直到某个节点没有左子树为止,接着换个方向搜索右子树,图示如下:
2)广度优先搜索
与深度搜索不同的是这种搜索的方式总是按照层次进行的,当前层所以节点都访问过后才会继续往下,图示如下:
3. 深度优先搜索算法框架
void DFS(当前节点){ 对当前节点的访问;`在这里插入代码片` 标记当前节点为已访问; for(下一节点 : 当前节点的邻接列表){ 剪枝(如果下一节点已经访问过就跳过); DFS(下一节点); } }
1)二叉树深度优先搜索模板
//二叉树前序DFS搜索 void DFS(TreeNode* root){ if(root == nullptr) return; cout << root->val << " "; //输出当前节点 //这里不需要标记当前节点为已访问,因为二叉树不会往回走 DFS(root->lchild); DFS(root->rchild); }
调整输出节点的位置,还能得出另外两种二叉树DFS遍历:
//二叉树中序DFS搜索 void DFS(TreeNode* root){ if(root == nullptr) return; DFS(root->lchild); cout << root->val << " "; //输出当前节点 DFS(root->rchild); } //二叉树后序DFS搜索 void DFS(TreeNode* root){ if(root == nullptr) return; DFS(root->lchild); DFS(root->rchild); cout << root->val << " "; //输出当前节点 }
2)图深度优先搜索模板
vector<int> visited; //用来标记已访问节点 void DFS(Graph *G, int v){ cout << v << " "; //输出当前节点 visited[v] = 1; //标记当前节点为已访问 for(int w = 0; w < G->vexnum; w++){ if(!visited[w]) DFS(G, w); } }
3)二维矩阵深度优先搜索模板
int m = matrix.size(); //行数 int n = matrix[0].size(); //列数 vector<vector<int>> visited(m, vector<int>(n, 0)); //用来标记已经访问过的节点 int directions[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //行进方向 void DFS(vector<vector<int>> &matrix, int x, int y){ if(matrix[x][y] == target) return; visited[x][y] = 1; //标记当前节点为已访问 for(int i = 0; i < 4; i++){ int new_x = x + directions[i][0]; int new_y = y + directions[i][1]; //这里一定要把visites[new_x][new_y]放在最后,因为计算后的new_x和new_y值有可能已经超过visited的下标访问范围 if(new_x < 0 || new_x >= m || new_y < 0 || new_y >= n || visited[new_x][new_y]) continue; DFS(matrix, new_x, new_y); } }
4. 广度优先搜索算法框架
首先需要明确的就是,广度优先搜索是按照层次遍历的,所以广度优先搜索不能像深度优先搜索一样使用递归来实现,广度优先搜索需要申请辅助队列来记录下一层需要遍历的节点
1)单源广度优先搜索
从一个起点出发到一个终点结束
//单源的广度优先搜索 int BFS(elemType start, elemType target) { queue<elemType> q; //申请辅助队列 set<elemType> visited; //标记已访问过的,避免走回头路 q.push(start); //起点入队列 visited.insert(start); //标记起点 int step = 0; //记录步数 while (!q.empty()) { int sz = q.size(); //每一层的元素个数 for (int i = 0; i < sz; i++) { elemType cur = q.pop(); //获得队列中的元素 if (cur == target) { //判断是否需要结束搜索 return step; } for (elemType x : cur.neighbor()) { //确定下一层需要搜索的节点 if (visited.find(x) == visited.end()) { q.push(x); visited.insert(x); } } } step++; // 步数加一 } }
2)多源广度优先搜索
顾名思义,多源广度优先搜索的意思是可以从多个起点开始向外进行搜索,是一种扩散式的搜索方法,如下图所示,图中值为0的点表示起点,则与每个0上下左右相邻的节点值就为1,同样与每个1上下左右相邻的节点值就为2。
vector<vector<int>> mulBFS(vector<vector<int>>& mat) { int m = mat.size(); int n = mat[0].size(); vector<vector<int>> dist(m, vector<int>(n, 0)); //记录每个位置上的步数 vector<vector<int>> visited(m, vector<int>(n, 0)); //用来标记是否访问过 queue<pair<int, int>> q; //第一步就是将多个源点按顺序入队列 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (mat[i][j] == 0) { q.push(pair<int, int>(i, j)); visited[i][j] = 1; } } } while (!q.empty()) { int sz = q.size(); for (int i = 0; i < sz; i++) { auto [x, y] = q.front(); q.pop(); for (int j = 0; j < 4; j++) { int new_x = x + directions[j][0]; int new_y = y + directions[j][1]; if (new_x < 0 || new_x >= m || new_y < 0 || new_y >= n || visited[new_x][new_y]) continue; q.push(pair<int, int>(new_x, new_y)); visited[new_x][new_y] = 1; dist[new_x][new_y] = dist[x][y] + 1; } } } }
[注]:上述的两种广度优先搜索中我们给出了两个记录步长的方式,第一种是设置一个step,然后每向前一步就step++,这种比较适合单源的广度优先搜索;第二种是设置一个辅助dist数组,记录所有节点的距离,然后通过 dist[newNode] = dist[oldNode]+1 进行更新,这种比较适合多源的广度优先搜索。
3)双向广度优先搜索
广度优先搜索是求图中最短路径的方法,一般是从某个起点出发,一直穷举直到碰到某个结束值(也就是目标值),这样的搜索过程就是单向的搜索,而有的题目即会提供起点位置,也会提供终点的位置,这样的题目可以采用双向的广度优先搜索, 当发现某一时刻两边都访问过同一顶点时就停止搜索。比如下面这个题目:
LeetCode 127. 单词接龙:在本题目中起始单词 beginword 和 结束单词 endword均已经给出,因此可以采用双向的广度优先搜索。
双向广度优先搜索算法流程:
1. 需要定义两个辅助队列,一个放前向搜索时的节点,一个存放逆向搜索时的节点
2. 查看两个辅助队列中是否有相同的元素,以判断搜索是否结束
3. 轮流进行搜索,也就是前向搜索进行一次后紧跟着就要做一次逆向搜索int BFS(string beginWord, string endWord, vector<string>& wordList) { unordered_set<string> wordSet(wordList.begin(), wordList.end()); if (wordSet.find(endWord) == wordSet.end()) return 0; unordered_set<string> q_start, q_end, visited; //双向搜索要定义两个set作为辅助队列 q_start.insert(beginWord); q_end.insert(endWord); int step = 1; while (!q_start.empty() && !q_start.empty()) { unordered_set<string> temp; //定义一个temp为了将q_start将q_end交换 for (string cur : q_start) { cout << cur << " "; if (q_end.find(cur) != q_end.end()) return step; //查看两个队列中是否有相同的元素,相同则结束遍历 //这一步很关键,单向BFS中是在新节点入队的同时加入访问数组,这里不行,因为我们结束查找的条件就是两个队 //列中是否有相同的条件,如果在新节点入队的同时加入访问数组,两个队列中就一定不会有相同的元素,因此要在判断后加 visited.insert(cur); for (int k = 0; k < cur.size(); k++) { string newWord = cur; for (int i = 0; i < 26; i++) { newWord[k] = i + 'a'; if (wordSet.find(newWord) != wordSet.end() && visited.find(newWord) == visited.end()) { temp.insert(newWord); } } } } step++; //交换搜索的方向 q_start = q_end; q_end = temp; } return 0; }
-
广度优先搜索(BFS)
2021-04-11 09:13:09宽度优先搜索(Breadth first Search,BFS),简称宽搜,又称广度优先搜索。它是从初始结点开始,应用产生式规则和控制策略生成第一层结点,同时检查目标结点是否在这些生成的结点中。若没有,再用产生式规则将所有第一层... -
C++搜索算法之广度优先搜索
2021-08-24 19:16:32广度优先搜索不同于深度优先搜多,它是一层层进行遍历的,因此需要先入先出的队列而非先入后出的栈进行遍历。由于是按层次进行遍历,广度优先搜索时按照“广”的方向进行遍历的,也常常用来处理最短路径问题。 2.... -
广度优先搜索详解
2019-08-19 14:45:56从题中可以看出,广度优先搜索适用问题:给定一幅图和一个起点s,寻找从起点s到给定目的点v是否存在路径,并找到最短的那条路径。 2、实现过程 如下图所示,寻找从出发点0到终点5的最短路径, 寻找过程和病毒扩散... -
深度优先搜索与广度优先搜索
2016-08-13 22:44:14在图的遍历中,有两种重要的遍历图的方式,即:深度优先搜索与广度优先搜索。 一、深度优先搜索。 深度优先搜索的基本思路是:按照某种条件一个劲儿的往下搜索,一旦遇到不符合条件的情况或者是走到尽头了就退回到... -
【HIT软件构造】广度优先搜索和深度优先搜索
2022-05-02 16:03:32广度优先搜索与深度优先搜索总结 -
广度优先搜索解决八数码问题
2021-01-08 09:08:51//程序描述:基于盲目搜索策略的宽度优先搜索方法 #include <iostream> #include <string> #include <cstring> #include <cmath> #include <vector> #include <queue> #... -
LeetCode常见题型——广度优先搜索
2022-03-04 23:18:43广度优先搜索(breadth-first search, BFS) 是层层遍历的。因此,需要用先入先出的队列。BFS常常用来处理最短路径问题。 -
一种基于广度优先搜索邻居的聚类算法 (2004年)
2021-05-09 17:10:01聚类算法BFSN广度优先搜索某对象的直接邻居和间接邻居,对符合条件的所有找到的邻居合并,从而完成一类聚类。接着重复该步骤完成所有对象的聚类。与同类算法相比,该算法具有实现简单、复杂度低和容易设定最佳参数等... -
广度优先搜索与深度优先搜索
2018-11-04 17:39:25广度优先搜索(宽度优先搜索,BFS)和深度优先搜索(DFS)算法的应用非常广泛,本篇文章主要介绍BFS与DFS的原理、实现和应用。 深度优先搜索 图的深度优先搜索(Depth First Search),和树的先序遍历比较类似。 它的... -
广度优先搜索算法(附C++实现)
2018-07-24 17:49:02在上一篇文章中,笔者介绍了DFS,这篇文章介绍的是图论的另一个经典算法--BFS(广度优先搜索算法)。 这一篇文章将对BFS作出介绍。队列的push操作将元素添加到队列的末尾,但pop操作将队列的第一个元素弹出,这与... -
[C++]广度优先搜索(BFS)(附例题)
2016-05-08 14:16:51广度优先搜索(BFS)(附例题)问题产生:Isenbaev是国外的一个大牛。现在有许多人要参加ACM ICPC。一共有n个组,每组3个人。同组的3个人都是队友。大家都想知道自己与大牛的最小距离是多少。大牛与自己的最小距离... -
广度优先遍历 实例
2016-08-02 15:17:20广度优先遍历作为一个初学者必备的技能,此资源免费,广度优先遍历是连通图的一种遍历策略。因为它的思想是从一个顶点V0开始,辐射状地优先遍历其周围较广的区域,故得名 -
深度优先搜索(DFS)与广度优先搜索(BFS)算法详解
2021-10-02 23:16:42深度优先搜索(DFS)与广度优先搜索(BFS)详解 1.广度优先搜索算法 1.1.前言 和树的遍历类似,图的遍历也是从图中某点出发,然后按照某种方法对图中所有顶点进行访问,且仅访问一次。 但是图的遍历相对树而言要更为... -
走迷宫问题(广度优先搜索) --- java实现
2021-11-30 21:00:34//得到队首元素 //四个方向开始搜索 for(int i = 0; i ; ++i) { Mypoint temp = new Mypoint(first.x+dir[i][0],first.y+dir[i][1],first); //判断走得通,且不越界 if(temp.x >= 1 && temp.x <= 8 && temp.y >= 1 ... -
【算法入门】广度/宽度优先搜索(BFS)
2012-04-30 02:58:22广度/宽度优先搜索(BFS) 【算法入门】 郭志伟@SYSU:raphealguo(at)qq.com 2012/04/27 1.前言 广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历策略。因为它的思想是从一个... -
图的广度优先搜索(bfs)以及深度优先搜索(dfs)
2020-02-09 11:43:581.前言 和树的遍历类似,图的遍历也是从图中某点出发...根据搜索路径的不同,我们可以将遍历图的方法分为两种:广度优先搜索和深度优先搜索。 2.图的基本概念 无向图:顶点对(u,v)是无序的,即(u,v)和(v,u)是... -
图的遍历——深度优先搜索和广度(宽度)优先搜索(含例题)
2019-02-01 21:56:40深度优先搜索 DFS基本思想 基本步骤: 1.从图中某个顶点v0出发,首先访问v0; 2.访问结点v0的第一个邻接点,以这个邻接点vt作为一个新节点,访问vt所有邻接点。直到以vt出发的所有节点都被访问到,回溯到v0的下... -
SWUST OJ#1069 图的按录入顺序广度优先搜索
2022-05-18 05:32:42图的广度优先搜索类似于树的按层次遍历,即从某个结点开始,先访问该结点,然后访问该结点的所有邻接点,再依次访问各邻接点的邻接点。如此进行下去,直到所有的结点都访问为止。在该题中,假定所有的结点以“A”--... -
C#,深度优先搜索(DFS)、广度优先搜索(BFS)算法的源代码与数据可视化
2022-03-29 08:26:54深度优先搜索算法DFS,广度优先搜索算法BFS是很基础的算法,也是大家很熟悉的。 一、深度优先搜索算法DFS,广度优先搜索算法BFS的基本概念 广度优先搜索算法类似于二叉树的层序遍历,是一种分层的查找过程,每向前... -
广度优先搜索(BFS)基本概念
2021-07-18 09:40:13宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于...