【C++】BFS杂讲

1,概述

BFS 是什么,它说"我是A*",它说“我是Dijkstra弱化版”,它说“我是”Flood fill“ ......,BFS 有很多种变形,而变形后也可以成为比较困难的问题,如 K短路问题 等等,所以我准备 水一期  将一讲 BFS 的一些常见的变形。

2,Flood Fill(洪水填充?)

顾名思义,就是从一个(或多个)起点开始扩张,知道满足条件的点全部求完才结束。文字可能不太好理解,所以我们放上几张图片qwq。

那么这就是洪水填充的总过程了qwq,遇到障碍物不填,从填的位置继续往下填,如果障碍物把方阵分成了多个连通块就分别处理qwq,那么到现在你一顶理解了洪水填充了对吧qwq。那么我们来做一道例题吧。P1596 [USACO10OCT] Lake Counting S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1596

 这题非常简单,甚至可以不用 Flood Fill 可以直接 dfs+标记来做,当然如果你自己想不出来,可以注册一个洛谷账号去查看题解,因为我们是讲解算法,所以就不把我的代码给放出来了qwq

3,最短路模型(走迷宫?)

接下来是 BFS 最常用的一种形式,他几乎包含了所有的 BFS 类型的题目,通常以 走迷宫 的形式出现,大概就是在一个图上给你一个起点,一个终点,然后给你一个行走的方式,请你求出最少要走多少步,才可以走到终点qwq

emmm因为这种类型的 BFS 很多变所以我们讲几个题目qwq

P1605 迷宫 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1605首先是这道最基础的走迷宫qwq,那么我们先分析一下题目,它给出了起点,终点,移动方式为上下左右,T 个障碍物,那么这就完美符合了我们 BFS最短路模型(其实最短路模型没这么局限),所以这道题我们也就迎刃而解了qwq,虽然我们是讲算法的,但是因为这种BFS不太好描述就放代码了 

#include<iostream>//个人建议不使用万能头文件,如果要使用万能头文件,就不能定义数组map;
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
int map[6][6];//地图;
bool temp[6][6];//走过的标记;
int dx[4]={0,0,1,-1};//打表;
int dy[4]={-1,1,0,0};//打表;
int total,fx,fy,sx,sy,T,n,m,l,r;//total计数器,fx,fy是终点坐标,sx,sy是起点坐标,T是障碍总数,n,m是地图的长和宽,l,r是障碍的横坐标和纵坐标;
void walk(int x,int y)//定义walk;
{
    if(x==fx&&y==fy)//fx表示结束x坐标,fy表示结束y坐标;
    {
        total++;//总数增加;
        return;//返回,继续搜索;
    }
    else
    {
        for(int i=0;i<=3;i++)//0——3是左,右,下,上四个方向;
        {
            if(temp[x+dx[i]][y+dy[i]]==0&&map[x+dx[i]][y+dy[i]]==1)//判断没有走过和没有障碍;
            {
                temp[x][y]=1;//走过的地方打上标记;
                walk(x+dx[i],y+dy[i]);
                temp[x][y]=0;//还原状态;
            }    
        } 
    }
}
int main()
{
    cin>>n>>m>>T;//n,m长度宽度,T障碍个数 
    for(int ix=1;ix<=n;ix++)
        for(int iy=1;iy<=m;iy++)
            map[ix][iy]=1;//把地图刷成1;
    cin>>sx>>sy;//起始x,y 
    cin>>fx>>fy;//结束x,y 
    for(int u=1;u<=T;u++)
    {
        cin>>l>>r;//l,r是障碍坐标;
        map[l][r]=0;
    }
    walk(sx,sy);
    cout<<total;//输出总数;
    return 0;
} //此处借用 ybb756032937 dalao 的代码

接下来是在序列上的 BFS qwq

P1588 [USACO07OPEN] Catch That Cow S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1588emmm 我们还是分析一下题目吧qwq,题目还是一如既往,给出农夫(起点),牛(终点),的位置,也给出了我们农夫走路的规则,可以发现这又是一道 BFS 的裸题!于是我们又放出了一个精美的代码qwq

#include<iostream>
#include<queue>
using namespace std;

typedef pair<int,int> P;// p.first 表示牛的位置,p.second表示牛走了多少步 
queue<P> que;
P p;

int main(){
    int t, FJ, Min;
    cin >> t;
    while( t -- ){
        cin >> FJ >> p.first;
        Min = 1000000;
        que.push( P(p.first,0) );
        while( que.size() ){
            p = que.front();
            que.pop();
            if( p.first < FJ ){//如果牛在FJ的后面
                p.second += FJ - p.first;
                if( Min > p.second ) Min = p.second;
            }else if( p.first % 2 == 0 ){//牛可以直接除以2,优先考虑除以2 
                if( p.first / 2 > FJ )
                    que.push( P(p.first/2,p.second+1) );
                else if( p.first - FJ > FJ - p.first/2 )//除以2 之后距离FJ近一些 
                    que.push( P(p.first/2,p.second+1) );
                else{//除以2 之后距离FJ的距离反而变远了,因此不考虑除以2,直接走到FJ那里去 
                    p.second += p.first - FJ;
                    if( Min > p.second ) Min = p.second;
                }
            }else{//如果不能直接y/2,选择y+1,y-1的方式 
                que.push( P(p.first+1,p.second+1) );
                que.push( P(p.first-1,p.second+1) );
            }
        }
        cout << Min << endl;
    }
    return 0;
}//借用 dalao YF1999 的代码qwq
4,多源BFS(这也行?)

如果你耐心看完了前面的几个部分,你会发现,到目前为止我们做过的 BFS 还都是单源(一个起点),那么多源该如何处理呢?其实和单源没多大区别,只不过就是把所有起点加进来而已,但是这样为什么对的呢?我们知道 BFS 是使用队列维护的,遵循先进先出,同一层的点,同时进入队列(大概这么理解就行)也就是说明我们所有源点扩张后,扩张到的点深度相同,也就是说对正确答案没有影响,所以我们来放一张图qwq(0,表示源点,绿色表示障碍物):

 OK,这下咱们又可以进入happy的水题时间了qwq,这回就不放代码了(图都给你了qwq)

P1332 血色先锋队 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1332这题因为一眼真,所以就不讲了qwq,不理解可以去看看题解qwq

5,双向广搜(甲乙两队同时施工?)

我们先来假设现在有一个贼炸裂的图,这个图每次用广搜搜一层,每层的点数都成指数上升,那么这时候我们的如果用单向搜索的话就会慢的离谱,但是!如果我们利用双向搜索,从终点和起点同时搜索,如果起点和终点搜到的点如果存在交汇,那么就说明可以连通,并且最小值就是当前的数值,那么,如果有一端搜完了怎么办?并且还没有交汇,就说明他们永远也联通不了,直接退出即可,所以。。。这就是双向广搜qwq,因为比较不好理解我就放个图qwq:

 这就是双向广搜的全部过程了qwq,其实双向广搜就是用来优化普通BFS的东西,它也从始至终不是什么算法,其实很多题都可以用双向广搜,就看你想不想了,有兴趣的小盆友可以把上面几道题用双向广搜搞一下,我就不放题目了qwq

emmm这就是这篇博客的全部了,后期我还会发DFS和A*算法qwq。

所以...点赞QAQ

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值