This repository has been archived by the owner on May 25, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
[算法]搜索初步: 从迷宫最短路问题来理解DFS和BFS #14
Comments
Locietta
added
C++
Associated with C++ language
C
algorithm
算法
progressing
开填了,但还没填完的
labels
Sep 12, 2020
DFS和BFS的比较DFS的范式: void dfs(int deep) { // 搜索深度/状态变量作为参数
if (符合某种要求||已经不能在搜了) { // 终止
做一些操作;
return;
}
if (符合某种条件且有地方可以继续搜索的) { //这里可能会有多种条件,可能要循环或者多写几个if什么的
a[x][y]='x';// 状态转移
dfs(deep+1,sum+1);// 递归调用,搜索下一层
a[x][y]='.';// 状态还原
}
} BFS的范式: int visit[N][N] //用来记录走过的位置
int dir[4][2]={0,-1,0,1,-1,0,1,0};
using status = tuple<int,int,int>; //一般是点,还有步数,也可以存其他的
queue<status> v;
void bfs(status p) {
status t,tt;
v.push(p);
while (!v.empty()) {
t=v.front(); //取出最前面的
v.pop(); //删除
if(找到符合条件的) {
做记录;
while(!v.empty()) v.pop(); //如果后面还需要用,随手清空队列
return;
}
visit[t.x][t.y]=1; //走过的进行标记,以免重复
rep(i,0,4) { //做多次查找
tt=t;
tt.x+=dir[i][0];tt.y+=dir[i][1]; //这里的例子是向上下左右查找的
if(如果这个位置符合条件) {
tt.bits++; //步数加一
v.push(tt); //把它推入队列,在后面的时候就可以用了
}
}
}
}
|
终于摸完了( ̄▽ ̄)" |
这里是不是这个意思: #include <stdio.h>
int map[50][50], n, count, length;
void dfs(const int step, int i, int j) {
if (i == n - 1 && j == n - 1) {
count++;
if (step < length) length = step;
return;
}
// map[i][j] = 1;
// 这里是不是就不用了?否则好像会重复,因为在dfs进来之前就已经转移状态了?
// 不知道理解的对不对,那这样的话main函数调用dfs(0,0,0)的时候是不是也要先把 map[0][0] 设置为1?
if (i && !map[i - 1][j]) { // left
map[i-1][j] = 1;
dfs(step + 1, i - 1, j);
map[i-1][j] = 0;
}
// up
// right
// down
// map[i][j] = 0;
}
int main(void) {
while (scanf("%d", &n) != EOF) {
count = 0, length = __INT_MAX__;
for (int i = 0; i < n; ++i) { // read
for (int j = 0; j < n; ++j) {
scanf("%d", &map[i][j]);
}
}
map[0][0] = 1; // 这里这么加一句理解对吗?
dfs(0,0,0);
count ? printf("%d\n", length) : puts("No solution");
}
return 0;
} |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
搜索初步: DFS和BFS
第一篇算法,从最基础的搜索开始。
所谓搜索算法,也就是从某个状态出发,按照一定顺序遍历所有能到达的状态来解决问题的办法。一般来说,按照搜索顺序的不同,主要分为深度优先搜索(DFS) 和 广度优先搜索(BFS) 两种手段。
这里我们用一个经典的搜索问题:迷宫最短路问题 来看看这两种搜索方式具体是什么,又有什么异同。
深度优先DFS
什么是DFS?
所谓的深度优先指的是从某个状态开始,不断地转移到下一个状态,直到不能继续转移为止,这时候返回前一步,转移到其他的状态,直到到达解状态。
emmm有亿点抽象,那...具体在这个迷宫问题上来看呢?
在迷宫问题上翻译一下深度优先的定义的话:就是说从某个格子出发,不断地往四周的格子走,如果考虑不走回头路的话,那么总会出现不能继续走的情况。这时候,退回到上一步,在上一步走其他的路,如果上一步没有其他的路可走了就再退回到上一步......不断重复这个过程,直到走到终点为止。
这就很直观了,就像一个人通过试错法来走迷宫的过程:先一路走到死路,然后回到前一步选另一条路,不断地试错,这样就遍历了所有能走的路。事实上也就是一种回溯法。
画成搜索树的话就是这样👇
这个搜索过程对应LIFO的栈结构:不断push新的状态入栈,不能继续时,pop出最后push的状态,push另一个状态。而众所周知,所有的栈操作和递归函数是等价的,所以DFS通常用递归来实现。
DFS的代码实现
先来看看DFS解迷宫问题的C++代码(顺便也练习了一下面向对象和STL):
Walker
类完成了所有的操作,利用pair
来保存状态(也就是走到的位置)。为了简明,它直接继承自STL的stack,其中构造函数完成读取的操作,dfs()
实现DFS,next()
是DFS状态转移的精髓。所有的DFS都有类似
next()
的代码:状态转移→递归调用→状态还原。只要掌握了这个,所有的DFS就都会写了。当然栈和面向对象语言都是不必要的(这里主要是我想练习一下刚学的C++(逃)),我们来看C语言的版本:
仅28行,单纯依靠
dfs()
递归来实现,注意下面的这段代码👇是很经典的状态转移→递归调用→状态还原模式。
看,是不是很容易~
广度优先BFS
什么是BFS?
BFS和DFS很类似,区别只在于搜索的顺序不同:BFS总是先搜索距离初始状态近的状态。
也就是说,它是按照 开始状态→1次转移可以到达的所有状态→2次转移可以到达的所有状态→…… 这样的顺序进行搜索。
在迷宫的例子里,就是说我们按照走1步能到达的位置,走2步能到达的位置...这样的顺序逐一搜索,直到不再有能到达的位置。
想象我们拿着地图,画出一系列的“等高线”,先标距离为1的,再标距离为2的,直到地图上的每一个位置都被标上了要到达所需的步数。
画成搜索树的话就是这样👇
这个搜索过程对应 FIFO 的队列结构:enqueue加入一层的状态,再dequeue丢出最先加入的那一层状态。当然由于BFS依赖于“步数”的概念,所以有时也可以考虑直接利用循环来实现。
BFS的代码实现
BFS的C++代码(夹杂了各种私货,主要是为了练习新学的C++,不过应该还是清楚的(大概))
因为BFS对应于队列操作,所以让
Walker
类继承自deque
,同样重载构造函数用于读入数据,利用tuple<i,j,step>
来保存状态。next()
函数将下一步的所有可能加入队列,并将上一步的状态移除,并维护一个step
变量用于指示现在是第几步。当发现能到达终点时,输出步数。当然实际上我们仔细思考的话,“地图”和状态完全可以二合一,我们可以把状态信息(这里也就是步数)直接标在地图上,这样一来就可以不用队列来实现这个迷宫BFS.
按照这样的思路,我们可以写出相应的C代码:
用了一些技巧把代码压到了30行,思路还是比较简单的。按照步数step循环,最终判断有没有到达过终点。简单的用循环实现了BFS。
The text was updated successfully, but these errors were encountered: