DFS(深度优先搜索),BFS(广度优先搜索)小总结

这周正在学习DFS和BFS。
体验中觉得这两个算法还是挺好用的,但是遇到某些数据大的情况就很容易超时。(所以到后面还是得学习一下如何优化,或者采用更佳的搜索方法来解决问题)
然后学习了一段时间,感觉基本上了解了DFS和BFS的基础实现原理以及应用(不过我认为还是得通过做题来培养自己的感觉,什么时候该采取DFS,什么时候该采用BFS),它们两者间各自的优势需要通过实际的问题来具体分析,根据它们各自的特点来应用于不同的问题中才能获得最优的性能。

总的来说,两者都是搜索方法 (这不是废话嘛!) ,但是两者的搜索方式却有极大的区别。
我将DFS比作莽夫,就是一条路莽下去,如果有分支路,就选择其中一条走下去,直到走到终点或者该点处没有路可以走了,这时候只能回头,走之前没有走过的分支,继续莽下去。
而BFS更像是水流。我们在最上层倒水下来,水会流向这个节点处的各个分支,逐层地开始搜索。

由于DFS的特性,我们会采用 递归的方式来实现。
具体模板:

void dfs()//参数用来表示状态,例如临界条件,达到终点的条件  
{  
    if(到达终点状态)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    if(特殊状态)//剪枝(避免搜索不必要的地方)
        return ;
    for(扩展方式)  
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            tag标记;  
            dfs();  
            还原tag标记;     // dfs很重要一点就是可能要采用回溯思想,视题目而定  
        }  

    }  
}  

例题: HDU 1241 油田问题
AC代码如下:

#include <iostream>
using namespace std;
const int maxn=1e3;
char a[maxn][maxn]; // 用来储存油田矩阵
int dir[8][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{-1,1},{1,-1},{-1,-1} }; //八个方向
int m,n; //m是行 n是列
void dfs(int x,int y)
{
    int tx,ty;
    for(int i=0;i<8;i++)
    {
        tx=x+dir[i][0]; //tx,ty分别是 下一个坐标代表的x,y; 
        ty=y+dir[i][1];
        if( tx>=0 && tx<=m && ty>=0 && ty<=n ) //说明没有越界那么就继续搜下去
        {
            if(a[tx][ty]=='@') //使@变成* 
            {
                a[tx][ty]='*';
                dfs(tx,ty); //继续dfs深搜
            }
        }
    }
}
int main()
{
    while( cin>> m >> n && m && n )
    {
        for(int i=0;i<m;i++)
            cin>>a[i];
        int sum=0;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
            {
                if(a[i][j]=='@') //如果遍历到一个@ 说明找到一个油田块
                {
                	 a[i][j]='*';
                    sum++;
                    dfs(i,j); //消除油田
                }
            }
        cout<<sum<<endl;
    }
    return 0;
}

BFS 基本实现就采用 队列的方式

queue< pos > q;
// pos是一个struct 带有 x,y坐标 (用来表示二维数组的下标)
q.push(首节点);
while(!q.empty())
{
    pos temp=q.front();
    q.pop();
    isok[temp.x][temp.y]=true; //标记该点已经走过了
    for(int i=0;i<4;i++)
    {
        int tx=temp.x+dir[i][0];
        int ty=temp.y+dir[i][1];
        if( tx < n && tx>=0 && ty >=0 && ty < m && !isok[tx][ty] && s[tx][ty]=='.')
        {
            isok[tx][ty]=!isok[tx][ty]; //标记该点已经走过了
            q.push(pos(temp.x+dir[i][0],temp.y+dir[i][1])); // 将这个节点下的子节点插入至队列中。
        }
    }

猜你喜欢

转载自blog.csdn.net/weixin_43508782/article/details/85125929