0基础学算法 搜索篇第一讲 深度优先搜索

  相信绝大多数人对于深度优先搜索和广度优先搜索是不会特别陌生的,若是我这样说彷佛你没据说过,那若是我说dfs和bfs呢?先不说是否学习过它们,至少它们的大名应该是都是据说过的吧,深度优先搜索(Depth-First-Search)和广度优先搜索(Breadth-First-Search)同为搜索(Search)中的两个大类。顾名思义,他们的做用即是在必定的元素当中选取符合要求的元素,有些状况下不管你使用dfs或bfs都能得出结果,可是事实上它们两个本质上是有区别的html

第一讲深度优先搜索(Depth-First-Search)ios

  深度优先搜索是一种用途很普遍的算法,这种搜索方法使用的是一种比较基本的概念----递归,dfs就是基于递归而产生的一种严格意义上的算法,最开始的时候dfs是一种在开发爬虫早期使用较多的方法,它的目的是要达到被搜索结构的叶结点。那么深度优先搜索究竟是如何实现的呢?算法

  要能理解dfs,首先理解递归是必要的(递归连接https://www.cnblogs.com/qj-Network-Box/p/12729230.html),在理解了递归后,就能够来看看这种算法的思想了函数

  假如你要搜寻节点①~节点⑩,而后你经过遍历找到了节点①,那么接下来你可使用dfs找到接下来的节点学习

  找到第一个节点是必须的,而后就能够接着往下递归测试

 

而后就要一路找到底,即一直找到要回溯的节点网站

 

若是到了节点⑤的时候又找到了能够继续往下递归的条件,那么还能够继续往下搜索spa

 

而后在②处又找到了下面的一个节点3d

到了新的节点又能够向下搜搜code

虽然如今回溯到了①,可是搜索还差几步,由于①再往下还有节点

要一直等到这里才是dfs最终结束的地方

 

 以上即是dfs的基本思想了,可是呢dfs并非一种一成不变的算法,事实上不一样的状况下所写出来的dfs是不一样的,可是思路差很少就相似以上

深度优先搜索(Depth-First-Search)的例题

  在某个神奇的网站上,你总能够找到一些有趣的题巩固你学的知识,题目连接-->https://www.luogu.com.cn/problem/P1162

  这一道题算是一道比较基础的练习题吧(应该),其实这道题在你可以理解dfs的状况下,并找到思路的状况下应该是手到擒来的事。

  首先咱们来仔细地读一读题大概意思就是被1框住的0要改写成2,我想不少人看到题的第一反应是想着怎么区别圈里面和圈外面的0,而后把圈里面的0改为2,彷佛这个思路只有一个难点,那就是如何肯定一个0到底处在圈里仍是圈外,我开始也是这么想的,而后我想到了一个解决办法,以下图

通常的状况就如左图,因此我后来的分析都是基于左图的

 

 

而后我就想到了这个断定方法,也许你也想到了,可是我在实现这种方法的时候我发现了一个很大的瑕疵,假如那个圈不是规则的,并且不只不规则,并且仍是凹多边形这种思路就会出问题,问题以下图所示

 

 

若是测试点给的是这样图形,以前的断定方法就完全失效了,由于很明显这个原本是一个在圈外的点,却会被断定成圈内的,那到底该如何识别一个0究竟是圈外仍是圈内呢?说实话,我到如今仍是没想出来,可是不少时候咱们就可使用逆向思惟大法,既然很难断定是不是圈内的,那就反过来判断他是否是圈外的不就完了?首先咱们能够肯定一个0处于方阵边缘处确定不是圈内的,因此咱们能够经过这个方法能够先找到边缘的零,那么,与它相邻的0以及相邻于与他相邻的0定然也是在圈外的,那么这道题dfs的思路也好说了,找到一个圈外边缘的0,标记一下,而后搜索与他相邻的0,并标记后继续搜索,因为题目要求,咱们每到一点只要向周围四个方向搜索便可

供上搜索部分的代码

 1 int n,a[35][35]; 
 2 int x1[4]={0,1,0,-1};
 3 int y1[4]={1,0,-1,0};//四个方向
 4 void dfs(int x,int y)
 5 {
 6     a[x][y]=5;
 7     for(int i=0;i<4;i++)
 8     {
 9         if(x+x1[i]>=0&&x+x1[i]<n&&y+y1[i]>=0&&y+y1[i]<n)
10         {
11             if(a[x+x1[i]][y+y1[i]]==0)    dfs(x+x1[i],y+y1[i]);//dfs
12         }
13     }
14 }

可是这道题只搜索这一次确定是不够的,咱们还须要考虑其余状况,好比下图

这种状况下有两块不在圈内的区域,因此咱们须要不止一次地运行dfs,也就是说咱们在主函数中能够将他的边缘“走”一圈以确保每一块圈外的0均可以被标记到

 

 

供上主函数+dfs

#include<iostream>
using namespace std;
int n,a[35][35]; 
int x1[4]={0,1,0,-1};
int y1[4]={1,0,-1,0};
void dfs(int x,int y)
{
    a[x][y]=5;
    for(int i=0;i<4;i++)
    {
        if(x+x1[i]>=0&&x+x1[i]<n&&y+y1[i]>=0&&y+y1[i]<n)
        {
            if(a[x+x1[i]][y+y1[i]]==0)    dfs(x+x1[i],y+y1[i]);
        }
    }
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    {
        cin>>a[i][j];
    }
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    {
        if((i==0||i==n-1)&&a[i][j]==0) dfs(i,j);
        else if(i>0&&(j==0||j==n-1)&&a[i][j]==0) dfs(i,j);
    }
    pp();
    return 0;
}

如今的代码就能够实现把全部不在圈里的0标记成5,在圈里的不变,不过代码还差最后一步,由于咱们标记的时候将圈外的0标记成5,因此输出的时候要将全部是5的地方输出0,将本来是0的地方输出2,因此将这种输出处理一下就完成了

完整代码

#include<iostream>
using namespace std;
int n,a[35][35]; 
int x1[4]={0,1,0,-1};
int y1[4]={1,0,-1,0};
void pp()        
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(a[i][j]==5) cout<<0;
            else if(a[i][j]==1) cout<<1;
            else if(a[i][j]==0) cout<<2;
            cout<<" ";
        }
        cout<<endl;
    }
}
void dfs(int x,int y)
{
    a[x][y]=5;
    for(int i=0;i<4;i++)
    {
        if(x+x1[i]>=0&&x+x1[i]<n&&y+y1[i]>=0&&y+y1[i]<n)
        {
            if(a[x+x1[i]][y+y1[i]]==0)    dfs(x+x1[i],y+y1[i]);
        }
    }
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    {
        cin>>a[i][j];
    }
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    {
        if((i==0||i==n-1)&&a[i][j]==0) dfs(i,j);
        else if(i>0&&(j==0||j==n-1)&&a[i][j]==0) dfs(i,j);
    }
    pp();
    return 0;
}

本期的内容就到这里了,若是你以为对你有帮助,那么帮忙把赞👍点一下吧,若是还期待我往后的表现,就点个关注➕好了,咱们下期说说bfs,再见!

相关文章
相关标签/搜索