广度优先搜索,顾名思义,从一个节点一层一层的向目的节点搜索。本质上就是一个暴力搜索,枚举所有的可能,直到找到目的节点。
我们可以看一个例题:
输入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;
}
上面代码中借用了栈来保存最后的路径,当然也可以不用栈,可以再新开一个结构体数组依次记录,之后倒序输出即可。
总结:实际上,通过在结构体中新加两个变量就像是完成了链表指针的功能,一个指向一个,从而最后从一个节点向前找出了所有的节点。