营救 题解
作者:互联网
经典的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;
}
完结撒花✿✿ヽ(°▽°)ノ✿
标签:队列,int,题解,bfs,vis,哥伦比亚号,1005,营救 来源: https://www.cnblogs.com/joshuahxz210/p/15102970.html