BFS
BFS基础
BFS是什么?
BFS 是 Breadth First Search 的缩写,即广度优先搜索(也称宽度优先搜索)。
BFS 是搜索的手段之一。
BFS的作用是什么?
(1):求最短路径、最少操作
(2):求联通块(与 DFS 类似)
BFS的结构
BFS 的搜索路线是以一层一层、由近及远的顺序进行搜索的。
以一张图为例:
起始点为 a,终点为 f
求最少经过几个点能从点 a 到达点 f
第一层为起点,即点 a
第二层为点 a 能去到的位置,即点 b、c、d
第三层为点 b、c、d 能去到的位置,即点 e、f
此刻在第三层已经到达了点 f,即到达了终点。
那么我们便可以得出最少经过的点数了,即为 3 个点(a、d、f)
用圈层图来表示:从起点所在的第一层开始,搜到终点第一次出现对应的那层,然后结束,即为最外层。
用树状图来表示:从起点一直搜到终点
代码实现
在 BFS 中,我们需要用到一个队列,来实现一层一层访问节点的顺序。
代码框架
0、头文件
#include <stdio.h>
#include <string.h>
#include <queue>
1、准备结构体
// 开一个结构体
struct node {
int x, y; // 节点所在位置
int step; // 节点所在层数
}st, ed; // 起点和终点
2、编写 BFS 函数
以二维BFS为例
const int maxn = ...;
int gx, gy; // 终点的位置,在 main 里读入
int n, m; // 图的边界,在 main 里读入
bool vis[maxn][maxn]; // 记录位置是否被走过
int map[maxn][maxn]; // 建一个二维数组来存放图的内容
// 以四个方向为例:上下左右
int dx[4] = {0,0,-1,1};
int dy[4] = {1,-1,0,0};
int bfs(int x, int y)
{
queue<node>q; // 开一个队列
// 对起点初始化
st.x = x;
st.y = y;
st.step = 0; // 初始层次为 0
memset(vis, false, sizeof(vis));
vis[x][y] = true; // 标记初始位置已被走过
q.push(st); // 先将起点放入队列
while(!q.empty()) // 直到队列为空 或 找到终点后,终止循环
{
st = q.front(); // 将起点更新为队列中的第一个结构
q.pop(); // 然后将队列中第一个结构删除
// 找到终点,就结束函数,并返回此时层数
if(st.x==gx && st.y==gy)
return st.step;
for(int i=0; i<4; i++)
{
ed.x = st.x + dx[i];
ed.y = st.y + dy[i];
ed.step = st.step + 1; //层数加一
// 若该位置已走过,则进入下一循环,避免重复
// 若超出边界,则进入下一循环
// 其中 n、m 为边界
if(vis[ed.x][ed.y] || map[ed.x][ed.y]=='题目条件' || ed.x<0 || ed.x>=n || ed.y<0 || ed.y>=m)
continue;
vis[ed.x][ed.y] = true; //标记该位置已走过
// 若还未到终点,则将其放入队列,变成下次调用的起点
q.push(ed);
}
}
return -1; // 若找不到终点,则按题目要求返回特定值
}
3、编写 main 函数
int main()
{
int sx, sy; //起点
scanf("%d %d", &n, &m); //读入边界
scanf("%d %d", &sx, &sy); //读入起点
scanf("%d %d", &gx, &gy); //读入终点
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
scanf("%c", &map[i][j]);
if(sx==gx && sy==gy)
printf("0\n");
else
printf("%d\n", bfs(sx, sy));
return 0;
}
例题
一维BFS
主要目的是熟悉BFS代码
HDU-1548
#include <stdio.h>
#include <string.h>
#include <queue>
struct node {
int x;
int step;
} st, ed;
int gx;
int n;
int a[205];
bool vis[205];
int bfs(int x)
{
std::queue<node>q;
st.x = x;
st.step = 0;
memset(vis, false, sizeof(vis));
vis[x] = true;
q.push(st);
while(!q.empty())
{
st = q.front();
q.pop();
if(st.x==gx)
return st.step;
for(int i=-1; i<=1; i+=2)
{
ed.x = st.x + i * a[st.x];
ed.step = st.step + 1;
if(ed.x<=0 || ed.x>n || vis[ed.x])
continue;
vis[ed.x] = true;
q.push(ed);
}
}
return -1;
}
int main()
{
int sx;
while(scanf("%d", &n)!= EOF && n)
{
scanf("%d %d", &sx, &gx);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
if(sx==gx) printf("0\n");
else printf("%d\n", bfs(sx));
}
return 0;
}
HDU-2717
#include <stdio.h>
#include <string.h>
#include <queue>
struct node {
int x;
int step;
} st, ed;
const int maxn = 100005;
int gx;
bool vis[maxn];
int bfs(int x)
{
std::queue<node>q;
st.x = x;
st.step = 0;
memset(vis, false, sizeof(vis));
vis[x] = true;
q.push(st);
while(!q.empty())
{
st = q.front();
q.pop();
if(st.x == gx)
return st.step;
for(int i=0; i<3; i++)
{
if(i==0)
ed.x = st.x + 1;
else if(i==1)
ed.x = st.x - 1;
else if(i==2)
ed.x = st.x * 2;
ed.step = st.step + 1;
if(ed.x<0 || ed.x>maxn || vis[ed.x])
continue;
vis[ed.x] = true;
q.push(ed);
}
}
return 0;
}
int main()
{
int sx;
while(scanf("%d %d", &sx, &gx) != EOF)
{
if(sx >= gx)
{
printf("%d\n", sx - gx);
continue;
}
printf("%d\n", bfs(sx));
}
return 0;
}
二维BFS
大多数题目都是二维BFS,所以之前所写的代码框架也是按二维BFS来写的
HDU-1372
#include <stdio.h>
#include <queue>
struct node{
int x, y;
int step;
} st, ed;
int gx, gy;
int dx[8] = {-2,-2,2,2,-1,-1,1,1};
int dy[8] = {-1,1,-1,1,-2,2,-2,2};
int bfs(int x, int y)
{
std::queue<node>q;
st.step = 0;
st.x = x;
st.y = y;
q.push(st);
while(!q.empty())
{
st = q.front();
q.pop();
if(st.x==gx && st.y==gy)
return st.step;
for(int i=0; i<8; i++)
{
ed.x = st.x + dx[i];
ed.y = st.y + dy[i];
ed.step = st.step + 1;
if(ed.x<=0 || ed.x>8 || ed.y<=0 || ed.y>8) continue;
q.push(ed);
}
}
return -1;
}
int main()
{
int sx, sy;
char c1, c2;
while(scanf("%c%d %c%d", &c1, &sy, &c2, &gy) != EOF)
{
getchar();
sx = c1 - 'a' + 1;
gx = c2 - 'a' + 1;
if(sx==gx && sy==gy)
printf("To get from %c%d to %c%d takes 0 knight moves.\n", c1, sy, c2, gy);
else
printf("To get from %c%d to %c%d takes %d knight moves.\n",c1, sy, c2, gy, bfs(sx, sy));
}
return 0;
}
HDU-1728
这题比较特殊!!
如果一路不拐弯,那么 step 是不用增加的。
也就是说,只有拐弯后 step 才会整体都加一,所以这题要在一条直线中的每个点处都判断一次是否到达了终点,因此要在 for 里面(同一个方向)进行判断
#include <stdio.h>
#include <string.h>
#include <queue>
struct node {
int x, y;
int step;
} st, ed;
const int maxn = 105;
int gx, gy;
int n, m;
int k;
bool vis[maxn][maxn];
char map[maxn][maxn];
int dx[4] = {0,0,-1,1};
int dy[4] = {1,-1,0,0};
int bfs(int x, int y)
{
std::queue<node>q;
st.x = x;
st.y = y;
st.step = -1; // 这题从 -1 开始,因走第一步时相当于拐了一个弯
memset(vis, false, sizeof(vis));
vis[x][y] = true;
q.push(st);
while(!q.empty())
{
st = q.front();
q.pop();
for(int i=0; i<4; i++)
{
ed.x = st.x + dx[i];
ed.y = st.y + dy[i];
// 一路直走不拐弯
while(map[ed.x][ed.y] == '.' && ed.x>=1 && ed.x<=m && ed.y>=1 && ed.y<=n)
{
// 这题中 vis 是用来判断是否 q.push
if(!vis[ed.x][ed.y])
{
vis[ed.x][ed.y] = true;
ed.step = st.step + 1;
if(ed.x==gx && ed.y==gy && ed.step<=k)
return true;
q.push(ed);
}
ed.x += dx[i];
ed.y += dy[i];
}
}
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
int sx, sy;
while(T--)
{
scanf("%d %d", &m, &n);
getchar();
for(int i=1; i<=m; i++)
scanf("%s", map[i]+1);
scanf("%d %d %d %d %d", &k, &sy, &sx, &gy, &gx);
if(sx==gx && sy==gy)
{
printf("yes\n");
continue;
}
if(bfs(sx, sy))
printf("yes\n");
else
printf("no\n");
}
return 0;
}
三维BFS
HDU-2102
这题一定要先输入再处理!!!
这题一定要先输入再处理!!!
这题一定要先输入再处理!!!
不然就会像我一样失去两天的美好时光
这题的重点是处理传送门 ‘#’
围绕这一个问题会展开多个问题
1、若 ‘#’ 的那边是 ‘*’,则会撞死。
处理方法:将 ‘#’ 也改为 ‘*’
2、若 ‘#’ 的那边是也是 ‘#’,则会陷入死循环。
处理方法:将两个 ‘#’ 都改为 ‘*’
#include <stdio.h>
#include <string.h>
#include <queue>
struct node {
int x, y, z;
int step;
} st, ed;
const int maxn = 12;
int gx, gy, gz;
int n, m, t;
char map[2][maxn][maxn];
bool vis[2][maxn][maxn];
int dx[4] = {0,0,-1,1};
int dy[4] = {1,-1,0,0};
bool bfs(int x, int y, int z)
{
std::queue<node>q;
st.x = x;
st.y = y;
st.z = z;
st.step = 0;
memset(vis, false, sizeof(vis));
vis[z][x][y] = true;
q.push(st);
while(!q.empty())
{
st = q.front();
q.pop();
if(st.x==gx && st.y==gy && st.z==gz && st.step<=t)
return true;
for(int i=0; i<4; i++)
{
ed.x = st.x + dx[i];
ed.y = st.y + dy[i];
ed.z = st.z;
ed.step = st.step + 1;
if(map[ed.z][ed.x][ed.y]=='*' || vis[ed.z][ed.x][ed.y] || ed.x<0 || ed.x>=n || ed.y<0 || ed.y>=m)
continue;
vis[ed.z][ed.x][ed.y] = true;
if(map[ed.z][ed.x][ed.y]=='#')
ed.z = (ed.z + 1) % 2;
q.push(ed);
}
}
return false;
}
int main()
{
int T;
scanf("%d", &T);
int sx, sy, sz;
while(T--)
{
scanf("%d %d %d", &n, &m, &t);
for(int i=0; i<2; i++)
for(int j=0; j<n; j++)
scanf("%s", map[i][j]);
for(int i=0; i<2; i++)
{
for(int j=0; j<n; j++)
{
for(int k=0; k<m; k++)
{
if(map[i][j][k] == 'S')
{
sx = j, sy = k, sz = i;
}
else if(map[i][j][k]=='P')
{
gx = j, gy = k, gz = i;
}
else if(map[i][j][k] == '#' && map[(i+1)%2][j][k] == '#')
{
map[i][j][k] = '*';
map[(i+1)%2][j][k] = '*';
}
else if(map[i][j][k] == '#' && map[(i+1)%2][j][k] == '*')
{
map[i][j][k] = '*';
}
}
}
}
if(sx==gx && sy==gy && sz==gz)
{
printf("YES\n");
continue;
}
if(bfs(sx, sy, sz))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}