本文内容基于《算法笔记》和官方配套练题网站“晴问算法”,是我作为小白的学习记录,如有错误还请体谅,可以留下您的宝贵意见,不胜感激。
前言
深度优先搜索是一种枚举所有完整路径以遍历所有情况的搜索方法,总是以“广度”作为前进的关键词,采用队列实现。
一、广度优先算法概述
广度优先搜索属于搜索问题的一种,当问题可以被描述为“路径搜索”时,就可以采用搜素问题的所有解的方式来进行解决,所以BFS本质还是暴力。广搜也存在“岔道口”,只是当遇到“岔道口”时,需要将本层所有的岔道都走一遍,然后再走下一层的岔道,符合队列的“先进先出”思想。
广搜和深搜的共同点之一是只有一个起点,也就是说一次搜索只能遍历以一个点为起点的所有路径。
而BFS更适合需要搜索最优解的问题,BFS可以理解为层次遍历,也就是说如果BFS搜索到了一个满足问题的答案,那么这个答案肯定是“距离最近的”,是“最内层的”,那么就不需要继续向外层搜索了,所以BFS对比DFS更适合找最优解。但BFS需要的空间比DFS大,需要将一层的所有可能解都放入队列中,不像DFS那样是走完一条完整路径再去走另一条路(不过递归实现本身占用的内存还是挺大的,除非自己创建栈)。
二、算法设计
BFS设计的关键在于“岔路口”的抽象和“层次”在队列中的具体体现。
算法通用模板:
void BFS(int s) {
queue <int> q;
q.push(s);
while(!q.empty()){
取出队首元素top;
访问队首元素top;
将队首元素出队;
将top的下一层节点中未曾入队的节点全部入队,并设置为已入队;
}
}
1.数字操作

岔路口:加1或乘2;
目标:到达指定整数;
采用队列将起点1加入队首元素,将1取出,并访问1(判断是否满足条件),对1 + 1和1 * 2进行判断,如果满足入队条件(<=n)就入队,循环执行该过程直到队列为空(无解,但根据题意肯定有解)或者找到最优解。
记录本层长度,设置计数器,如果访问完本层所有元素则将计数器自加。可以设置一个bool数组记录被访问过的元素,如果元素被访问过就不需要重复访问,大大节省算法时间。
在实际的编码中,我并没有严格按照BFS的思路去写,而是在被访问元素的下一层节点入队时直接进行访问,这样可以节省一层的搜索量,不过我也不知道这样做到底好不好。
完整代码如下:
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
bool inQueue[MAXN + 1] = {
false};
int BFS(int n){
//1是起点,+1或*2是岔路口
queue <int> qe;
qe.push(1); //放入起点
int step = 0;
while(!qe.empty()){
int size = qe.size(); //记录本层长度
for(int i = 0; i <= size - 1; i++){
int top = qe.front(); //取出队首元素
qe.pop();
inQueue[top] = true;
if(top + 1 == n) return step + 1; //说明下一层
if(top + 1 <= n && !inQueue[top + 1]) qe.push(top + 1);
if(top * 2 == n) return step + 1;
if(top * 2 <= n && !inQueue[top * 2]) qe.push(top * 2);
}
step++; //层数加一
}
return -1; //到不了目标点
}
int main(){
int n;
scanf("%d", &n);
printf("%d", BFS(n));
}
2迷宫最短路径

岔路口:(x + 1 , y)(x - 1 , y) (x , y + 1) (x , y - 1)
目标:到达终点的最少步数对应的路径
套用BFS的标准模板进行搜索,这道题到没有说不可以返回原来的位置,但可以证明如果存在最短路径,那这条路径一定不存在返回原来的位置的情况,所以可以设置bool散列表判断坐标是否入过队,这样可以防止元素同一元素反复入队,大大节省搜索层数。
关键是如何保存走过的路径,这在DFS里很容易实现,但BFS是层次搜索,不像DFS那样走完一条完整路径才返回去走其他路径,所以并不能采用具体的存储结构存储走过的路径(那样将耗费巨大的存储空间),这里提供两种方法:(1)模拟链表,记录前驱节点位置;(2)DFS + BFS
第二个方法效率较低,这里使用第一种方法,具体操作是开一个类似二叉树的静态二叉链表,只是链表节点中的地址是前驱节点的下标,故只能反向遍历。
具体代码如下:这段代码在网站中运行时有一个数据点运行无结果,但我在DEV中可以运行出正确答案,搞不懂······
#include<cstdio> //关键在于如何记录走过的路径
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = 100;
int number[MAXN][MAXN] = {
}; //迷宫
int n , m; //列数和行数
int add1[] = {

(算法笔记)&spm=1001.2101.3001.5002&articleId=129708713&d=1&t=3&u=54ca68562be549c5aa4b2a324101858e)
3666

被折叠的 条评论
为什么被折叠?



