BFS简单总结(一些普通的BFS问题探讨)

BFS的总结

  • 这几天有点忙啊,没时间写,现在时间充裕了,更新会非常快滴
  • 博客不停滴
    好了开始启程吧

啥是BFS呢?

  • BFS又叫宽度优先搜索。
    他和他的老乡DFS的区别很明显,一个一条路走到黑,一个一层一层的走。(本质上他们都是搜索的方式,都是可以的,但是BFS有着最短路的特性,也决定了他是DFS无法取代的存在)

  • BFS的遍历方式
    BFS是一层一层的搜索的,所以具有最短路的特性
    (能用DFS解决的,一定可以用BFS,但BFS能解决的,DFS不一定可以)

    如图所示的遍历方式
    在这里插入图片描述

BFS的实现基础是队列,就是那个先进先出的队列(STL 的queue)
我们不需要手动实现,C++和其他语言都有相关的队列库
(当然,如果你喜欢,也可以自己写,我就不模拟了,嘻嘻)
在这里插入图片描述

BFS通过队列的形式就每一层的数据存进队列中,进行读取和记录,来查找最短路

先来一道经典的最短路迷宫问题
题目 - > 迷宫最短路问题

我们要去找到起始点到终点的最短路,只需要就每一个遍历的点的步数记录下来,从而求解问题。

其实很简单,他的操作和DFS几乎一模一样。也没什么区别,就是利用了一下BFS的特性记录步数来求解

代码如下

#include<iostream>
#include<queue>  //stl的队列
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
const int N=1010;
char ch[N][N];
int d[N][N];
int n,x1,y1,x2,y2;
int bfs(){
    
    
    int xx[]={
    
    -1,0,1,0},yy[]={
    
    0,1,0,-1};///遍历的方向数组
    queue<PII> q;
    q.push({
    
    x1-1,y1-1});
    d[x1-1][y1-1]=0;
    while(!q.empty()){
    
    
        auto t=q.front();
        q.pop();
        for(int i=0;i<4;i++){
    
    
            int fx=t.first+xx[i],fy=t.second+yy[i];
            if(fx<0||fy<0||fx==n||fy==n||d[fx][fy]!=-1||ch[fx][fy]=='1') continue; //进行判断
            d[fx][fy]=d[t.first][t.second]+1; //记录步数
            if(fx==x2-1&&fy==y2-1) return d[fx][fy];  //找到终点,输出答案
            q.push({
    
    fx,fy});
        }
    }
    return d[x2-1][y2-1];
}
int main(){
    
    
    memset(d,-1,sizeof d);
    cin>>n;
    for(int i=0;i<n;i++) cin>>ch[i]; //输入
    cin>>x1>>y1>>x2>>y2;
    cout<<bfs()<<endl;
    return 0;
}

还有一道差不多的遍历
马的遍历
本质上都是差不多的,只需要维护步数就行。

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef pair<int,int> PII;
const int N=405;
int d[N][N];
int n,m,x,y;
void bfs(){
    
    
    int xx[]={
    
    -2,-1,1,2,2,1,-1,-2},yy[]={
    
    1,2,2,1,-1,-2,-2,-1};
    queue<PII> q;
    q.push({
    
    x-1,y-1});
    d[x-1][y-1]=0;
    while(!q.empty()){
    
    
        auto t=q.front();
        q.pop();
        for(int i=0;i<8;i++){
    
    
            int fx=t.first+xx[i],fy=t.second+yy[i];
            if(fx<0||fy<0||fx>=n||fy>=m||d[fx][fy]!=-1) continue;
            d[fx][fy]=d[t.first][t.second]+1;
            q.push({
    
    fx,fy});
        }
    }
}
int main(){
    
    
    memset(d,-1,sizeof d);
    cin>>n>>m>>x>>y;
    bfs();
    for(int i=0;i<n;i++){
    
    
        for(int j=0;j<m;j++)
            printf("%-5d",d[i][j]);
        puts("");
    }
    return 0;
}

对于BFS的操作手法,不仅仅局限与最短路,也可以变相的求解别的问题
例如CF的一道BFS的题
BFS的应用题

这题本身很简单,就看你如何去写,我不建议用DFS(也是可以用),但BFS更适合这样题目
DFS+记忆搜索也可以解决最短路问题的,但BFS更简单一点

代码如下

#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
using namespace std;
string a;
bool check(string c){
    
       //判断是否满足幸运数子
    if(count(c.begin(),c.end(),'4')!=count(c.begin(),c.end(),'7')) return false;
    if(c.size()!=a.size()) return c.size()>a.size();
    for(int i=0;i<a.size();i++)
        if(c[i]!=a[i]) return c[i]>a[i];
    return true;
}
string bfs(){
    
       //BFS进行求解最小的幸运数字
    queue<string> q;
    q.push("4"); q.push("7");
    while(1){
    
    
        auto t=q.front();
        q.pop();
        string b=t+'4',c=t+'7';
        if(check(b)) return b;
        if(check(c)) return c;
        q.push(b),q.push(c);
    }
}
int main(){
    
    
    cin>>a;
    cout<<bfs()<<endl;
    return 0;
}

来一道属于BFS的洪水灌溉算法

题目 - > BFS

这和DFS的写法本质上是一样的(但BFS具有最短路程的特性)

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
const int N=105;
char ch[N][N];
int d[N][N];
int n,m,x,y;
int bfs(){
    
    
    int xx[]={
    
    -1,-1,-1,0,1,1,1,0},yy[]={
    
    -1,0,1,1,1,0,-1,-1}; //八联通
    int ans=0;
    queue<PII> q;
    q.push({
    
    x-1,y-1});
    d[x-1][y-1]=0;
    while(!q.empty()){
    
    
        auto t=q.front();
        q.pop();
        for(int i=0;i<8;i++){
    
    
            int fx=t.first+xx[i],fy=t.second+yy[i];
            if(fx<0||fy<0||fx>=n||fy>=m||d[fx][fy]!=-1||ch[fx][fy]=='*') continue;
            d[fx][fy]=d[t.first][t.second]+1;
            q.push({
    
    fx,fy});
            ans=max(ans,d[fx][fy]);
        }
    }
    return ans;
}
int main(){
    
    
    cin>>m>>n>>y>>x;
    memset(d,-1,sizeof d);
    for(int i=0;i<n;i++) cin>>ch[i];
    cout<<bfs()<<endl;
    return 0;
}

除了二维的最短路,还可以三维滴
题目 - > 三维的BFS
其实二维和三维的处理,是一摸一样的,只是让大家深刻的了解BFS

代码

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=105;
char ch[N][N][N];
int d[N][N][N];
int n,m,l,x1,y1,z1;
struct ss{
    
      //建立x,y,z;
    int x,y,z;   
};
int bfs(){
    
    
    int xx[]={
    
    -1,0,1,0,0,0},yy[]={
    
    0,1,0,-1,0,0},zz[]={
    
    0,0,0,0,1,-1}; //方向数组
    queue<ss> q;
    q.push({
    
    x1,y1,z1});
    d[z1][x1][y1]=0;
    while(!q.empty()){
    
    
        auto t=q.front();
        q.pop();
        for(int i=0;i<6;i++){
    
    
            int fx=t.x+xx[i],fy=t.y+yy[i],fz=t.z+zz[i];
            if(fx<0||fy<0||fz<0||fx==n||fy==m||fz==l||ch[fz][fx][fy]=='#'||d[fz][fx][fy]!=-1) continue;
            d[fz][fx][fy]=d[t.z][t.x][t.y]+1;
            if(ch[fz][fx][fy]=='E') return d[fz][fx][fy];
            q.push({
    
    fx,fy,fz});
        }
    }
    return -1;
}
int main(){
    
    
    while(cin>>l>>n>>m,l||n||m){
    
    
        memset(d,-1,sizeof d);
        for(int i=0;i<l;i++)
            for(int j=0;j<n;j++)
                cin>>ch[i][j];
        for(int i=0;i<l;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<m;k++)
                    if(ch[i][j][k]=='S') z1=i,x1=j,y1=k;
        int k=bfs();
        if(k!=-1) printf("Escaped in %d minute(s).\n",k);
        else puts("Trapped!");
    }
    return 0;
}

这里还有一道记录路径的BFS题(分享给大家)
BFS题

其实思路很简单,就是逆路程来记录路径就可以了

代码

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
const int N=1010;
int n;
bool st[N][N];
int p[N][N];
PII m[N][N];
int bfs(){
    
    
    int xx[]={
    
    -1,0,1,0},yy[]={
    
    0,1,0,-1};
    queue<PII> q;
    q.push({
    
    n-1,n-1});
    while(!q.empty()){
    
    
        auto t=q.front();
        q.pop();
        for(int i=0;i<4;i++){
    
    
            int fx=t.first+xx[i],fy=t.second+yy[i];
            if(fx<0||fy<0||fx>=n||fy>=n||st[fx][fy]||p[fx][fy]==1) continue;
            q.push({
    
    fx,fy});
            st[fx][fy]=true;
            m[fx][fy]=t;
        }
    }
}
int main(){
    
    
    cin>>n;
    memset(st,0,sizeof st);
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            cin>>p[i][j];
    bfs();
    PII end={
    
    0,0};
    cout<<0<<" "<<0<<endl;
    while(end.first!=n-1||end.second!=n-1){
    
    
        int x=end.first,y=end.second;
        end.first=m[x][y].first,end.second=m[x][y].second;
        printf("%d %d\n",end.first,end.second);
    }
    return 0;
}

对于BFS,我也没刷很多的题,主要是水平不允许我刷水平高滴题,哈哈
扎心了,老铁
本来想讲一下边权不同时的BFS,但自己都没整的很懂,所以还是算了吧
对于BFS来说,和DFS一起灵活运用,才是最重要的
DFS的写法,相比于BFS来说,简单很多,
但对于最短路的问题求解,还是要靠BFS来进行解决

灵活使用,才能发挥极致。

本来想贴一下y总的八数码的题,贴一些简单题(挺适合萌新学习图论,不至于劝退,哈哈)
算了,想看的话,自己看吧。

八数码

思想:降维+BFS

#include<iostream>
#include<queue>
#include<algorithm>
#include<unordered_map>
using namespace std;
string st;
int bfs(){
    
    
    string end="12345678x";
    queue<string>q;
    unordered_map<string,int>d;
    q.push(st);
    d[st]=0;
    int xx[]={
    
    -1,0,1,0},yy[]={
    
    0,1,0,-1};
    while(!q.empty()){
    
    
        auto t=q.front();
        q.pop();
        int dis=d[t];
        if(t==end) return dis;
        int k=t.find('x');
        int x=k/3,y=k%3;
        for(int i=0;i<4;i++){
    
    
            int fx=x+xx[i],fy=y+yy[i];
            if(fx<0||fy<0||fx==3||fy==3) continue;
            swap(t[k],t[fx*3+fy]);
            if(!d.count(t)){
    
    
                d[t]=dis+1;
                q.push(t);
            }
            swap(t[k],t[fx*3+fy]);
        }
    }
    return -1;
}
int main(){
    
    
    for(int i=0;i<9;i++){
    
    
        char x;
        cin>>x;
        st+=x;
    }
    cout<<bfs()<<endl;
}

解析 -> 八数码

谢谢大家的观看,点点赞吧
制作不易,嘻嘻

上面题目的话,可以做一下的,很有帮助的


日拱一卒无有尽

功不唐捐终入海

胡适


加油 0.0

猜你喜欢

转载自blog.csdn.net/m0_52361859/article/details/113246701