zoukankan      html  css  js  c++  java
  • 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:求解的个数
  • 相关阅读:
    如果男人是计算机,女人是软件(在开发过程中的偶然随想)
    C/C++ 可变参数函数的原理和应用
    Python学习记录Hello Word
    Unity 把数字,英文图片变成字体
    unity+Android+PC加载本地图片
    Python学习记录安装
    Android学习 问题与答案
    Android 第三方 APK 包的静默安装
    Android学习 问题与答案 (2)
    JNI 之 HelloWorld
  • 原文地址:https://www.cnblogs.com/kirk-notes/p/14302801.html
Copyright © 2011-2022 走看看