深度优先搜索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;
}
};