跳到主要内容

宽度优先搜索(BFS)算法之一——最短路径

2.1 马的遍历 P1443

有一个 n×mn \times m 的棋盘,在某个点 (x,y)(x, y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。

输入数据格式

输入只有一行四个整数,分别为 n,m,x,yn, m, x, y

输出数据格式

一个 n×mn \times m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 1-1)。

输入输出样例

输入 #1输出 #1
3 3 1 1
0 3 2
3 -1 1
2 1 4

说明与提示

数据规模与约定

对于全部的测试点,保证 1xn4001 \leq x \leq n \leq 4001ym4001 \leq y \leq m \leq 400

参考代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
int vis[405][405]; //方格

struct Tnode{ //队列
int x,y;
} qu[405*405];
int dx[8]={-1,-2,-2,-1,1,2,2,1};
int dy[8]={2,1,-1,-2,2,1,-1,-2};//8个方向

void bfs(int x0, int y0) {
int head=0,tail=0; //队列的头和尾

qu[0].x = x0; //开始位置进队列
qu[0].y = y0;
tail++;
vis[x0][y0]=0; //记录到x,y的步数,同时也充当探索标记(=-1 表示没有探索过)

int ans=0;
while (head<tail){//队列非空
int x = qu[head].x; //取队列的头
int y = qu[head].y;
head++; //出队列
int step = vis[x][y]; //父节点到x,y所需要的步数

for (int d=0; d<8; d++) {
int nx=x+dx[d]; //四周坐标
int ny=y+dy[d];

if (nx>=1 && nx<=n && ny>=1 && ny<=m && vis[nx][ny]==-1){ //可以进入
vis[nx][ny]=step+1;

qu[tail].x = nx; //进队列
qu[tail++].y = ny;

}
}
}
return;
}

int main(){
int x,y;
cin >> n >> m >> x>>y;
//for(int i=1;i<=n;i++)
// for(int j=1;j<=m;j++)
// vis[i][j]=-1;
memset(vis,0xff,sizeof(vis));
bfs(x,y);

for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
cout<<vis[i][j]<<" ";
cout<<"\n";
}

return 0;
}

2.2 离开中山路 P1746

爱与愁大神买完东西后,打算坐车离开中山路。现在爱与愁大神在 x1,y1x_1,y_1 处,车站在 x2,y2x_2,y_2 处。现在给出一个 n×n(n1000)n \times n(n \le 1000) 的地图,00 表示马路,11 表示店铺(不能从店铺穿过),爱与愁大神只能垂直或水平着在马路上行进。爱与愁大神为了节省时间,他要求最短到达目的地距离(每两个相邻坐标间距离为 11)。你能帮他解决吗?

输入数据格式

11 行包含一个数 nn

22 行到第 n+1n+1 行:整个地图描述(00 表示马路,11 表示店铺,注意两个数之间没有空格)。

n+2n+2 行:四个数 x1,y1,x2,y2x_1,y_1,x_2,y_2

输出数据格式

只有 11 行,即最短到达目的地距离。

输入输出样例

输入 #1输出 #1
3
001
101
100
1 1 3 3
4

说明与提示

对于 20%20\% 数据,满足 1n1001\leq n \le 100

对于 100%100\% 数据,满足 1n10001\leq n \le 1000

参考代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
string vis[1005]; //方格
int step[1000][1000];

struct Tnode{ //队列
int x,y;
} qu[1000005];
int dx[4]={-1,0,+1,0};
int dy[4]={0,+1,0,-1};//4个方向

void bfs(int x0, int y0) {
int head=0,tail=0; //队列的头和尾

qu[0].x = x0; //开始位置进队列
qu[0].y = y0;
tail++;
vis[x0][y0]=0; //记录到x,y的步数,同时也充当探索标记(=-1 表示没有探索过)

int ans=0;
while (head<tail){//队列非空
int x = qu[head].x; //取队列的头
int y = qu[head].y;
head++; //出队列

for (int d=0; d<4; d++) {
int nx=x+dx[d]; //四周坐标
int ny=y+dy[d];
if (nx>=0 && nx<n && ny>=0 && ny<n&&vis[nx][ny]=='0'){ //可以进入
vis[nx][ny]='2';
step[nx][ny]=step[x][y]+1;
cout<<nx<<"-"<<ny<<endl;

qu[tail].x = nx; //进队列
qu[tail++].y = ny;

}
}
}
return;
}

int main(){

cin>>n;
for(int i=0;i<n;i++)
cin>>vis[i];
//memset(vis,0xff,sizeof(vis));
int x,y,x2,y2;
cin >> x >> y >> x2>>y2;
bfs(x-1,y-1);

cout<<step[x2-1][y2-1];
return 0;
}

2.3 岛屿的最大面积

给定一个由 0 和 1 组成的n*m矩阵 ,用来表示海洋岛屿地图。一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 矩阵的四个边缘都被 0(代表水)包围着。

找到给定的二维数组中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

例如: 小岛面积

输出的结果是:

6

输入格式

第一行2个正整数n和m,范围[4,1000]。 下面 n行每个行 m个数,都是0或1。

输出格式

1个整数,答案。

输入/输出例子1

输入:
3 3
0 0 1
1 1 0
1 1 1
输出:
5

参考代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[1002][1002]; //方格
int ans=0;

struct Tnode{ //队列
int x,y;
} qu[1000000];
int dx[4] = { 0, 1, 0,-1}; //四个方向
int dy[4] = {-1, 0, 1, 0};

void BFS(int x0, int y0) {
qu[0].x = x0; //开始位置进队列
qu[0].y = y0;
a[x0][y0]=0;
int head=0; //队列的头和尾
int tail=1;
while (head<tail){//队列非空
int x = qu[head].x; //取队列的头
int y = qu[head].y;
head++; //出队列
for (int d=0; d<4; d++) {
int nx=x+dx[d]; //四周坐标
int ny=y+dy[d];
if (a[nx][ny]==1){ //可以
qu[tail].x = nx; //进队列
qu[tail++].y = ny;
a[nx][ny]=0; //访问过标记
}
}
}
if (tail>ans)
ans=tail;
}

int main(){

cin >> n >> m;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
cin >> a[i][j];

for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
if ( a[i][j]==1)
BFS(i,j);
cout << ans;
return 0;
}

扩展练习:

  1. 马的遍历
  2. 离开中山路
  3. 好奇怪的游戏
  4. 路障
  5. 奇怪的电梯
  6. 血色先锋队

*学习笔记

暂没有学习笔记,快来抢first blood !