BFS的总结
- 这几天有点忙啊,没时间写,现在时间充裕了,更新会非常快滴
- 博客不停滴
好了开始启程吧
啥是BFS呢?
-
BFS又叫宽度优先搜索。
他和他的老乡DFS的区别很明显,一个一条路走到黑,一个一层一层的走。(本质上他们都是搜索的方式,都是可以的,但是BFS有着最短路的特性,也决定了他是DFS无法取代的存在) -
BFS的遍历方式
BFS是一层一层的搜索的,所以具有最短路的特性
(能用DFS解决的,一定可以用BFS,但BFS能解决的,DFS不一定可以)如图所示的遍历方式
BFS的实现基础是队列,就是那个先进先出的队列(STL 的queue)
我们不需要手动实现,C++和其他语言都有相关的队列库
(当然,如果你喜欢,也可以自己写,我就不模拟了,嘻嘻)
BFS通过队列的形式就每一层的数据存进队列中,进行读取和记录,来查找最短路
先来一道经典的最短路迷宫问题
题目 - > 迷宫最短路问题
我们要去找到起始点到终点的最短路,只需要就每一个遍历的点的步数记录下来,从而求解问题。
其实很简单,他的操作和DFS几乎一模一样。也没什么区别,就是利用了一下BFS的特性记录步数来求解
代码如下
#include<iostream>
#include<queue> //stl的队列
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
const int N=1010;
char ch[N][N];
int d[N][N];
int n,x1,y1,x2,y2;
int bfs(){
int xx[]={
-1,0,1,0},yy[]={
0,1,0,-1};///遍历的方向数组
queue<PII> q;
q.push({
x1-1,y1-1});
d[x1-1][y1-1]=0;
while(!q.empty()){
auto t=q.front();
q.pop();
for(int i=0;i<4;i++){
int fx=t.first+xx[i],fy=t.second+yy[i];
if(fx<0||fy<0||fx==n||fy==n||d[fx][fy]!=-1||ch[fx][fy]=='1') continue; //进行判断
d[fx][fy]=d[t.first][t.second]+1; //记录步数
if(fx==x2-1&&fy==y2-1) return d[fx][fy]; //找到终点,输出答案
q.push({
fx,fy});
}
}
return d[x2-1][y2-1];
}
int main(){
memset(d,-1,sizeof d);
cin>>n;
for(int i=0;i<n;i++) cin>>ch[i]; //输入
cin>>x1>>y1>>x2>>y2;
cout<<bfs()<<endl;
return 0;
}
还有一道差不多的遍历
马的遍历
本质上都是差不多的,只需要维护步数就行。
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef pair<int,int> PII;
const int N=405;
int d[N][N];
int n,m,x,y;
void bfs(){
int xx[]={
-2,-1,1,2,2,1,-1,-2},yy[]={
1,2,2,1,-1,-2,-2,-1};
queue<PII> q;
q.push({
x-1,y-1});
d[x-1][y-1]=0;
while(!q.empty()){
auto t=q.front();
q.pop();
for(int i=0;i<8;i++){
int fx=t.first+xx[i],fy=t.second+yy[i];
if(fx<0||fy<0||fx>=n||fy>=m||d[fx][fy]!=-1) continue;
d[fx][fy]=d[t.first][t.second]+1;
q.push({
fx,fy});
}
}
}
int main(){
memset(d,-1,sizeof d);
cin>>n>>m>>x>>y;
bfs();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
printf("%-5d",d[i][j]);
puts("");
}
return 0;
}
对于BFS的操作手法,不仅仅局限与最短路,也可以变相的求解别的问题
例如CF的一道BFS的题
BFS的应用题
这题本身很简单,就看你如何去写,我不建议用DFS(也是可以用),但BFS更适合这样题目
DFS+记忆搜索也可以解决最短路问题的,但BFS更简单一点
代码如下
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
using namespace std;
string a;
bool check(string c){
//判断是否满足幸运数子
if(count(c.begin(),c.end(),'4')!=count(c.begin(),c.end(),'7')) return false;
if(c.size()!=a.size()) return c.size()>a.size();
for(int i=0;i<a.size();i++)
if(c[i]!=a[i]) return c[i]>a[i];
return true;
}
string bfs(){
//BFS进行求解最小的幸运数字
queue<string> q;
q.push("4"); q.push("7");
while(1){
auto t=q.front();
q.pop();
string b=t+'4',c=t+'7';
if(check(b)) return b;
if(check(c)) return c;
q.push(b),q.push(c);
}
}
int main(){
cin>>a;
cout<<bfs()<<endl;
return 0;
}
来一道属于BFS的洪水灌溉算法
题目 - > BFS
这和DFS的写法本质上是一样的(但BFS具有最短路程的特性)
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
const int N=105;
char ch[N][N];
int d[N][N];
int n,m,x,y;
int bfs(){
int xx[]={
-1,-1,-1,0,1,1,1,0},yy[]={
-1,0,1,1,1,0,-1,-1}; //八联通
int ans=0;
queue<PII> q;
q.push({
x-1,y-1});
d[x-1][y-1]=0;
while(!q.empty()){
auto t=q.front();
q.pop();
for(int i=0;i<8;i++){
int fx=t.first+xx[i],fy=t.second+yy[i];
if(fx<0||fy<0||fx>=n||fy>=m||d[fx][fy]!=-1||ch[fx][fy]=='*') continue;
d[fx][fy]=d[t.first][t.second]+1;
q.push({
fx,fy});
ans=max(ans,d[fx][fy]);
}
}
return ans;
}
int main(){
cin>>m>>n>>y>>x;
memset(d,-1,sizeof d);
for(int i=0;i<n;i++) cin>>ch[i];
cout<<bfs()<<endl;
return 0;
}
除了二维的最短路,还可以三维滴
题目 - > 三维的BFS
其实二维和三维的处理,是一摸一样的,只是让大家深刻的了解BFS
代码
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=105;
char ch[N][N][N];
int d[N][N][N];
int n,m,l,x1,y1,z1;
struct ss{
//建立x,y,z;
int x,y,z;
};
int bfs(){
int xx[]={
-1,0,1,0,0,0},yy[]={
0,1,0,-1,0,0},zz[]={
0,0,0,0,1,-1}; //方向数组
queue<ss> q;
q.push({
x1,y1,z1});
d[z1][x1][y1]=0;
while(!q.empty()){
auto t=q.front();
q.pop();
for(int i=0;i<6;i++){
int fx=t.x+xx[i],fy=t.y+yy[i],fz=t.z+zz[i];
if(fx<0||fy<0||fz<0||fx==n||fy==m||fz==l||ch[fz][fx][fy]=='#'||d[fz][fx][fy]!=-1) continue;
d[fz][fx][fy]=d[t.z][t.x][t.y]+1;
if(ch[fz][fx][fy]=='E') return d[fz][fx][fy];
q.push({
fx,fy,fz});
}
}
return -1;
}
int main(){
while(cin>>l>>n>>m,l||n||m){
memset(d,-1,sizeof d);
for(int i=0;i<l;i++)
for(int j=0;j<n;j++)
cin>>ch[i][j];
for(int i=0;i<l;i++)
for(int j=0;j<n;j++)
for(int k=0;k<m;k++)
if(ch[i][j][k]=='S') z1=i,x1=j,y1=k;
int k=bfs();
if(k!=-1) printf("Escaped in %d minute(s).\n",k);
else puts("Trapped!");
}
return 0;
}
这里还有一道记录路径的BFS题(分享给大家)
BFS题
其实思路很简单,就是逆路程来记录路径就可以了
代码
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
const int N=1010;
int n;
bool st[N][N];
int p[N][N];
PII m[N][N];
int bfs(){
int xx[]={
-1,0,1,0},yy[]={
0,1,0,-1};
queue<PII> q;
q.push({
n-1,n-1});
while(!q.empty()){
auto t=q.front();
q.pop();
for(int i=0;i<4;i++){
int fx=t.first+xx[i],fy=t.second+yy[i];
if(fx<0||fy<0||fx>=n||fy>=n||st[fx][fy]||p[fx][fy]==1) continue;
q.push({
fx,fy});
st[fx][fy]=true;
m[fx][fy]=t;
}
}
}
int main(){
cin>>n;
memset(st,0,sizeof st);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>p[i][j];
bfs();
PII end={
0,0};
cout<<0<<" "<<0<<endl;
while(end.first!=n-1||end.second!=n-1){
int x=end.first,y=end.second;
end.first=m[x][y].first,end.second=m[x][y].second;
printf("%d %d\n",end.first,end.second);
}
return 0;
}
对于BFS,我也没刷很多的题,主要是水平不允许我刷水平高滴题,哈哈
扎心了,老铁
本来想讲一下边权不同时的BFS,但自己都没整的很懂,所以还是算了吧
对于BFS来说,和DFS一起灵活运用,才是最重要的
DFS的写法,相比于BFS来说,简单很多,
但对于最短路的问题求解,还是要靠BFS来进行解决
灵活使用,才能发挥极致。
本来想贴一下y总的八数码的题,贴一些简单题(挺适合萌新学习图论,不至于劝退,哈哈)
算了,想看的话,自己看吧。
思想:降维+BFS
#include<iostream>
#include<queue>
#include<algorithm>
#include<unordered_map>
using namespace std;
string st;
int bfs(){
string end="12345678x";
queue<string>q;
unordered_map<string,int>d;
q.push(st);
d[st]=0;
int xx[]={
-1,0,1,0},yy[]={
0,1,0,-1};
while(!q.empty()){
auto t=q.front();
q.pop();
int dis=d[t];
if(t==end) return dis;
int k=t.find('x');
int x=k/3,y=k%3;
for(int i=0;i<4;i++){
int fx=x+xx[i],fy=y+yy[i];
if(fx<0||fy<0||fx==3||fy==3) continue;
swap(t[k],t[fx*3+fy]);
if(!d.count(t)){
d[t]=dis+1;
q.push(t);
}
swap(t[k],t[fx*3+fy]);
}
}
return -1;
}
int main(){
for(int i=0;i<9;i++){
char x;
cin>>x;
st+=x;
}
cout<<bfs()<<endl;
}
解析 -> 八数码
谢谢大家的观看,点点赞吧
制作不易,嘻嘻
上面题目的话,可以做一下的,很有帮助的
日拱一卒无有尽
功不唐捐终入海
–胡适
加油 0.0