浅谈广度优先搜索bfs

广度优先搜索,顾名思义,从一个节点一层一层的向目的节点搜索。本质上就是一个暴力搜索,枚举所有的可能,直到找到目的节点。
我们可以看一个例题:
输入n,m表示二维数据的大小(1<=n,m<=1000),仅有0,1数字组成。一个人想要从左上角走到右下角(只能横竖走),若数组中元素为1则表示不能通过,0表示能通过。问你需要的最少步数是多少。
5 5
0 1 0 0 0
0 1 0 1 0
0 1 0 1 0
0 0 0 1 0
0 1 0 1 0

样例输出:
14
AC代码:

#include<iostream>
#include<queue>
#define maxn 1005
using namespace std;
int n,m;
struct node{
 int x,y,l;//这里的l表示到坐标为(x,y)的步数
};
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
bool vis[maxn][maxn];
int map[maxn][maxn];
bool check(int x,int y){
 if(x>=1&&x<=n&&y>=1&&y<=m&&!vis[x][y]&&!map[x][y])return true;
 return false;
}
int bfs(){
 queue<node>q;
 node s;s.x=1,s.y =1,s.l =0;
 q.push(s);
 vis[s.x ][s.y ]=1;
 while(!q.empty() ){
  node u=q.front() ;q.pop() ;
  if(u.x ==n&&u.y ==m){
   return u.l ;
  }
  for(int i=0;i<4;i++){
   int tx=u.x +dx[i];
   int ty=u.y +dy[i];
   if(check(tx,ty)){
    node temp;temp.x =tx;temp.y =ty;
    temp.l =u.l+1;
    q.push(temp);
    vis[tx][ty]=1; 
   }
  }
 } 
}
int main(){
 cin>>n>>m;
 for(int i=1;i<=n;i++){
  for(int j=1;j<=m;j++){
   cin>>map[i][j];
  }
 }
 cout<<bfs()<<endl;
 return 0;
}

这道题还可以加深一下,题目中可以叫你输出最少步数的路线。
这时,需要在节点上再加点东西from表示当前节点的上一个节点是哪个节点,id表示当前节点的编号。然后就只需在bfs过程中,使用另开的一个结构体数组(这里是ans[ ]数组)记录一次需要进队列的节点。起始点的id=0。AC代码:

#include<iostream>
#include<queue>
#include<stack>
#define maxn 1005
using namespace std;
int n,m;
struct node{
 int x,y,l;
 int id,from;
 node(){
  x=y=l=id=from=-1;
 }
}ans[maxn*maxn];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
bool vis[maxn][maxn];
int map[maxn][maxn];
bool check(int x,int y){
 if(x>=1&&x<=n&&y>=1&&y<=m&&!vis[x][y]&&!map[x][y])return true;
 return false;
}
void bfs(){
 queue<node>q;
 node s;s.x=1,s.y =1,s.l =0;
 s.id =0;
 q.push(s);
 vis[s.x ][s.y ]=1;
 int id=0;
 ans[0]=s;
 stack<node>p;
 while(!q.empty() ){
  node u=q.front() ;q.pop() ;
  if(u.x ==n&&u.y ==m){//这里到达了目的节点。
   while(u.from >=0){//所以,就需要从当前节点一直找到起始点,并将这些节点都依次按入栈中。
    p.push(u);
    u=ans[u.from ]; 
   }
   p.push(s);//别忘了起始点s。最后依次从栈中输出。
   while(!p.empty() ){
    node temp=p.top() ;
    printf("(%d, %d)\n",temp.x ,temp.y );
    p.pop() ;
   } 
   return ;
  }
  for(int i=0;i<4;i++){
   int tx=u.x +dx[i];
   int ty=u.y +dy[i];
   if(check(tx,ty)){
    id++;
    node temp;temp.x =tx;temp.y =ty;
    temp.l =u.l+1;
    temp.id =id;temp.from =u.id ;//很好理解,u是下一步u经过的节点的前一个节点
    q.push(temp);
    vis[tx][ty]=1; 
    ans[id]=temp;
   }
  }
 } 
}
int main(){
 cin>>n>>m;
 for(int i=1;i<=n;i++){
  for(int j=1;j<=m;j++){
   cin>>map[i][j];
  }
 }
 bfs();
 return 0;
}

上面代码中借用了栈来保存最后的路径,当然也可以不用栈,可以再新开一个结构体数组依次记录,之后倒序输出即可。
总结:实际上,通过在结构体中新加两个变量就像是完成了链表指针的功能,一个指向一个,从而最后从一个节点向前找出了所有的节点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值