BFS & DFS

BFS & DFS

DFS(Deep First Search)深度优先搜索

BFS(Breath First Search)广度优先搜索

Content

  一、BFS

  二、DFS

  三、知识拓展——队列

一、BFS

适用场景

一般用于求最优解

核心思想

  1. 规定搜索方向

  2. 利用二维数组模拟地图,并且多开一张地图用来标记地图是否走过

  3. 将起始位置信息存入队列后,取出起始位置信息,再将起始位置所有的搜索方向内存在的可行点依次存入队列,完成当前点所有方向的遍历后,再取出队列内的其它点,按照起始位置的方式依次遍历并存入队列。

  4. 我们所有的操作都是为了寻找每个位置点内的信息。而这个点是否为可行点取决于标记地图内存储的信息,当然每次放一个点进入队列都要将这个点所在的标记地图上做标记,以此表明此点已遍历。我们要搜索的信息主要是在我们从队列内取出点是做判断。

思维图解

 

  上图表示搜索此图中有多少红色色块

  图中虽然只看到 黄色色块单向移动,但实际上它会以一个点为中心判断它的八个方向,依次是上、左上、左、左下、下、右下、右、右上,如果存在零,就将它标记为1。

  注意理解前面的二十个色块的遍历过程就可以了。

  每当黄色色块到达的地方会做标记和检测内容,每次到达都会判断当前位置是否储存了红色色块信息,我们在代码中添加一个计数变量,在搜索完图时即可获得图中红色色块的数量信息。

  当然,BFS的运用不止于此,还可以迷宫寻路、搜索二叉树等许多操作。

BFS可行代码

int red_number = 0;
char mp[105][105];                       //开图
int fx[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; //定义运动方向的先后顺序
int fy[8] = {0, 1, 1, 1, 0, -1, -1, -1}; //移动方向是上、左上、左、左下、下、右下、右、右上
bool vis[105][105];                      //标记地图的数组 判断是否走过
struct node
{
    int x1, y1;
}; //坐标信息

void bfs(int x, int y)
{
    queue<node> q;     //定义队空间q,声明该队储存数据为node型
    q.push({x, y});    //用push()函数给队空间放入元素
    while (!q.empty()) //队空间非空就执行循环
    {
        node now = q.front(); //定义node型变量now并初始化为队空间最靠前的一个数据
                              //front()函数可以取出队列内最靠前的数据
        q.pop()               //用pop()函数删除最靠前的一个数据
            for (int i = 0; i < 8; i++)
        {
            int newx = now.x1 + fx[i];
            int newy = now.y1 + fy[i]; //按方向顺序移动位置,检测起点周围的八个方向位置中的信息
            if (mp[newx][newy] == 'R' && newx >= 0 && newx < n && newy >= 0 &&
                newy < m && !vis[newx][newy]) //判断地图可行点  在地图内且没有走过
            {
                red_number++;
                q.push({newx, newy}); //八个符合要求的方向放入队列,用于之后的搜索
                vis[newx][newy] = 1;  //将遍历过的位置标记为1
            }
        }
    }
    return;
}

二、DFS

适用场景

用于寻找可行解的个数

核心思想

利用递归按照规定方向寻找目标,当找到不可行路时,会原路返回到上一个岔路口,去找新的路,直到遍历完所有。(看似简单,难以理解 =_=)

思维图解

 

  同样的,每个当前位置,会遍历它的八个方向(与BFS相同)找到可行方向就会继续调用DFS函数如果8个方向被封死,DFS就会退回到上一个DFS(色块回到上一个位置),重新找其它可行点,直到找到终点@(也可以为别的标识符),或者被完全封死。

可行代码

int red_number = 0;
char mp[105][105];                       //开图
int fx[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; //定义运动方向的先后顺序
int fy[8] = {0, 1, 1, 1, 0, -1, -1, -1}; //移动方向是上、左上、左、左下、下、右下、右、右上
bool vis[105][105];                      //标记地图的数组 判断是否走过

void dfs(int x, int y)
{
    for (int i = 0; i < 8; i++)
    {
        int newx = x + fx[i];
        int newy = y + fy[i]; // 按方向移动
        if (mp[newx][newy] == '@' && newx >= 0 && newx < n && newy >= 0 &&
            newy < m && !vis[newx][newy]) // 判断可行点
        {
            vis[newx][newy] = 1; // 标记
            dfs(newx, newy);     // 函数递归
        }
    }
    return;
}

三、知识拓展——队列

头文件:#include <queue>

队列相当于是一个上下空洞、左右封闭的空间,元素从上面进入队列(用push() 函数添加元素),元素会按照存入循序从下往上排好,当使用front() 函数时仅仅可以读取队列最下面的那个元素,所以通常情况下,我们会在读取元素后用pop() 函数删除队列最下面的元素。

当我们放入的元素不止一个类型时,我们就要考虑使用结构体了,例如我们的BFS在给对立元素时是以坐标形式传入,所以结构体绑定不同的数据一定要掌握。

图解队列

  

写在最后

学无止尽,Kirk很开心你可以看完这篇文章,不知道对你有没有什么帮助,如果对文章有什么疑惑,或者你看出了文章有什么问题,可以私信KIrk哦,同时也欢迎所有想学习编程的readers前来交流,Kirk对来者都不拒的哦,祝各位readers学习编程愉快!!!

看完文章学完知识可以去练练手脚,这里推荐两个题:

  1. 油田问题

  2. 迷宫问题

最后奉上全套代码(针对油田问题)

#include <cstring>
#include <iostream>
#include <queue>  //队列
using namespace std;

int n, m;
char mp[105][105];
int fx[8] = {-1, -1, 0, 1, 1, 1, 0, -1};  
int fy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
bool vis[105][105];
struct node {
    int x1, y1;
};

void bfs(int x, int y) {
    queue<node> q;
    q.push({x, y});
    while (!q.empty()) {
        node now = q.front();
        q.pop();
        for (int i = 0; i < 8; i++) {
            int newx = now.x1 + fx[i];
            int newy = now.y1 + fy[i];
            if (mp[newx][newy] == '@' && newx >= 0 &&
                    newx < n && newy >= 0 &&
                    newy < m && !vis[newx][newy]) {  //判断地图可行点
                q.push({newx, newy});
                vis[newx][newy] = 1;
            }
        }
    }
    return;
}

void dfs(int x, int y) {
    for (int i = 0; i < 8; i++) {
        int newx = x + fx[i];
        int newy = y + fy[i];
        if (mp[newx][newy] == '@' && newx >= 0 &&
                newx < n && newy >= 0 &&
                newy < m && !vis[newx][newy]) {
            vis[newx][newy] = 1;
            dfs(newx, newy);
        }
    }
    return;
}

int main() {
    while (cin >> n >> m && n) {
        int sum = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) cin >> mp[i][j];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (mp[i][j] == '@' && !vis[i][j]) {
                    vis[i][j] = 1;
                    dfs(i, j);
                    sum++;
                }
            }
        }
        cout << sum << endl;
    }
    return 0;
}

//BFS:求最优解
//DFS:求解的个数
原文地址:https://www.cnblogs.com/kirk-notes/p/14302801.html