经典的bfs题,有详解

申明:有不同的意见可以评论或私信我。

题目:营救

铁塔尼号遇险了!他发出了求救信号。距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快赶到那里。

通过侦测,哥伦比亚号获取了一张海洋图。这张图将海洋部分分化成 n*n 个比较小的单位,其中用 1 标明的是陆地,用 0 标明是海洋。船只能从一个 0 格子,移到相邻的四个格子中的一个 0 格子。

为了尽快赶到出事地点,哥伦比亚号最少需要走多远的距离。

输入

第一行为 n。

下面是一个 n*n 的 0、1 矩阵,表示海洋地图, n<=1000

最后一行为四个小于 n 的整数,分别表示哥伦比亚号铁塔尼号的位置。

输出

哥伦比亚号到铁塔尼号的最短距离。


样例输入

3

001

101

100

1 1 3 3

样例输出

4


步骤详解

那么像这种有坐标的题目,首先要搞坐标结构体,尤其是 bfs。

struct Node{
int x,y;
};

对于方向,最基本的 direction 定量也要写好。

const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};

当然因为有结构体也可以搞点花里胡哨的。(不过我觉得更麻烦了不是么)

const Node dir[4]={{1,0},{-1,0},{0,1},{0,-1}};

接着就是其他的变量

int n;
int pgx,pgy/*哥伦比亚号坐标*/;
int ptx,pty/*铁塔尼号坐标*/;
int vis[1005][1005]/*查重和步数*/;
int mp[1005][1005]/*地图*/;
queue<Node> q;//队列

其中 vis 很重要!!!

这里还给大家推荐一个妙招(不是)

bool in(int x,int y){     return 1<=x&&x<=n&&1<=y&&y<=n;       } 

但是不知道大家有没有注意到啊,输入是没有空格的。

所以我们的输入程序要这么写:

cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%1d",&mp[i][j]);
cin>>pgx>>pgy>>ptx>>pty;

由于我们的vis不仅要查重,还要计算步数,故我们拿 -1 和 0 来查重0 及以上拿来算步数

memset(vis,-1,sizeof vis);

我直接把bfs用int返回值,用void当然也可以玩,所以输出可以这样写:

cout<<bfs(pgx,pgy);

那我们可以开始看核心 bfs 怎么写了。

首先要清楚 bfs 的模板

void bfs(/*起始点*/) {
/*将起始点放入队列中*/;
/*标记起点访问*/;
while(/*如果队列不为空*/) {
/*访问队列中队首元素*/;
/*删除队首元素*/;
for(/*x 所有相邻点*/) {
if(/*判断条件,不越界&&不阻拦&&未走过*/) {
/*将该点加入队列末尾*/;
/*标记该点已访问*/;
}
}
}
/*队列为空,广搜结束*/;
}

那现在这题的 bfs 变成了这样:

int bfs(int a,int b){//起始点坐标 
q.push({a,b});//将起始点放入队列
vis[a][b]=0;//标记
while(!q.empty()){//如果队列不为空
Node xy=q.front();//访问队首元素
q.pop();//删除队首元素
for(int i=0;i<4;i++){//所有相邻点
int xx=xy.x+dx[i],yy=xy.y+dy[i];//相邻点坐标
if(in(xx,yy)&&!mp[xx][yy]&&vis[xx][yy]==-1){//判断条件,不越界&&不阻拦&&未走过
q.push({xx,yy});//加入队列末尾
vis[xx][yy]=vis[xy.x][xy.y]+1;//标记已访问,顺便标记步数
}
}
}
return vis[ptx][pty];//最后的标记即总步数
}

下面是所有代码

#include<bits/stdc++.h>
using namespace std;
struct Node{
int x,y;
};//坐标结构体
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};/*方向*/
int n,pgx,pgy/*哥伦比亚号坐标*/,ptx,pty/*铁塔尼号坐标*/;
int vis[1005][1005]/*查重和步数*/
bool mp[1005][1005]/*地图*/;
queue<Node> q;//队列
bool in(int x,int y){
return 1<=x&&x<=n&&1<=y&&y<=n;
}//范围判断函数
int bfs(int a,int b){//起始点坐标
q.push({a,b});//将起始点放入队列
vis[a][b]=0;//标记
while(!q.empty()){//如果队列不为空
Node xy=q.front();//访问队首元素
q.pop();//删除队首元素
for(int i=0;i<4;i++){//所有相邻点
int xx=xy.x+dx[i],yy=xy.y+dy[i];//相邻点坐标
if(in(xx,yy)&&!mp[xx][yy]&&vis[xx][yy]==-1){//判断条件,不越界&&不阻拦&&未走过
q.push({xx,yy});//加入队列末尾
vis[xx][yy]=vis[xy.x][xy.y]+1;//标记已访问,顺便标记步数
}
}
}
return vis[ptx][pty];//最后的标记即总步数
}
int main(){
cin>>n;
memset(vis,-1,sizeof vis);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%1d",&mp[i][j]);//注意输入,没有空格
cin>>pgx>>pgy>>ptx>>pty;
cout<<bfs(pgx,pgy);
return 0;
}

完结撒花✿✿ヽ(°▽°)ノ✿