• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jk-2048
博客园    首页    新随笔    联系   管理    订阅  订阅
深度优先搜索DFS、广度优先搜索BFS

深度优先搜索DFS

基本概念

深度优先搜索(Depth-First Search,DFS)是十分常见的图搜索方法之一。
深度优先搜索会沿着一条路径一直搜索下去,在无法搜索时,回退到刚刚访问过的节点。
它从初始节点出发,按预定的顺序扩展到下一个节点,然后从下一节点出发继续扩展新的节点,不断递归执行这个过程,直到某个节点不能再扩展下一个节点为止。
因此深搜有一句典型的句子来描述,就是:不撞南墙不回头!
以当前所在位置为起点,沿着一条路向前走,当碰到岔道口时,选择其中一个岔路前进。
如果选择的这个岔路前方是一条死路,就退回到这个岔道口,选择另一个岔路前进。如果岔路中存在新的岔道口,那么仍然按上面的方法枚举新岔道口的每一条岔路。这样,只要迷宫存在出口,那么这个方法一定能够找到它。
 
深度优先搜索是模拟的一种算法,属于搜索算法,相比于广度优先搜索的代码要短一点,但是它比广搜较难理解,毕竟人家的递归可不是吹的……深搜的想法是首先选取一个未访问的点作为源节点。从源节点选取一条路一直往下走,沿着当前顶点的边,访问这条路线,直到走不下去为止。这时返回上一顶点,继续试探访问此顶点的其余子顶点,直到当前顶点的子顶点都被访问过,那么,返回上一顶点,继续重复。从而实现遍历。
 

应用场景

深搜也属于递归的一种算法,主要可以解决的问题是:有多少种方案(计算方案数),判断能否到达终点
但是它无法算出共有几步,如果要计算几步的话,需要用广搜(广度优先搜索)
void fun(int x,int y){
        int tx,ty;
        if(满足条件)
        输出/方案数加一;
        else
        for(int i=0;i<4;i++)   //遍历所有可行的待扩展点
        {
            tx=dx[i]+x,ty=dy[i]+y;    //切换点的坐标,以扩展点作为新的起点
            if(不越界,没走过,可以走)  //判断待扩展点是否可行
            {
                标记走过;      //标记已经走过
                fun(tx,ty);   //向下递归深搜
                回溯(可有可无)
            }
        }
}

算法思想

扩展访问顺序

深度优先遍历的秘籍:后访问的节点,其邻接点先被访问。
根据深度优先遍历的秘籍,后来的先服务,这可以借助“栈”来实现。递归本身就是使用“栈”实现的,因此使用递归的方法更方便。
深度优先遍历图的方法是,从图中某顶点v出发: 1、访问顶点v; 2、依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问; 3、若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。
 

算法流程

step1、初始化图中的所有节点为均未被访问。
step2、从图中的某个节点v出发,访问v并标记其已被访问。
step3、依次检查v的所有邻接点w,如果w未被访问,则从w出发进行深度优先遍历
(递归调用,重复步骤(2)和(3),以扩展节点为新的起点)
访问到尽头时,回到上一个节点,按顺序检查下一条岔路
step3中有一个重点是对邻接点的访问顺序
 

深度优先搜索示例程序

int path[A];
bool st[A];         //标记是否被搜过的数组
void dss(int u )
{
    if(u==n)   //如果遍历到底了就输出
    {
        for(int i = 0; i < n ; i++)
        cout<<path[i]<<" ";
        cout<<endl;
        return;//回到上一层
    }
    //当u<n时,说明还没填完。
    for(int i = 1 ; i<= n ;i ++)
    {
        if(!st[i])//如果这层i没有被用过。
        {
            path[u] = i;//u深度赋值为i
            st[i] = true;//标记i已近被用过。
            dss(u + 1);   //进入下一层
            st[i] = false;  
            //回溯时候要把i重新回到未标记的状态,不用恢复path[u] = 0是因为它会被覆盖
            //然后继续循环
            //循环完了后依然会回到上一层
        }
    }
}
 

广度优先搜索BFS

MC流水搜索
降谷羽WaterWay方法,属于广度优先搜索
方法一:广度优先搜索
思路及算法
我们从给定的起点开始,进行广度优先搜索。每次搜索到一个方格时,如果其与初始位置的方格颜色相同,就将该方格加入队列,并将该方格的颜色更新,以防止重复入队。WATER-WAY算法
注意:因为初始位置的颜色会被修改,所以我们需要保存初始位置的颜色,以便于之后的更新操作

示例程序

class Solution {
public:
    const int dx[4] = {1, 0, 0, -1};
    const int dy[4] = {0, 1, -1, 0};
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) 
        {
        int currColor = image[sr][sc];
        if (currColor == color) {
            return image;
        }
        int n = image.size(), m = image[0].size();
        queue<pair<int, int>> que; //open表,队列,用二元数对存坐标
        que.emplace(sr, sc);  //将坐标加入队列
        image[sr][sc] = color; //改色
        while (!que.empty())  //大循环:open队列不为空时
        {
            //需要复习STL队列数据结构
            //每次对队列中第一个坐标判断扩展
            int x = que.front().first, y = que.front().second;
            que.pop();
            for (int i = 0; i < 4; i++) //四方向入队列
            {
                int mx = x + dx[i], my = y + dy[i];
                if (mx >= 0 && mx < n && my >= 0 && my < m && image[mx][my] == currColor) 
                {
                    que.emplace(mx, my);
                    //可扩展,放入open队列
                    image[mx][my] = color;
                }
            }
        }
        return image;
    }
};

 

posted on 2024-02-23 17:19  JK降谷羽  阅读(61)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3