BSF深度优先遍历的练习
程序员文章站
2022-05-20 16:46:17
...
广度优先遍历类似于树中的层序遍历
以迷宫探索为例,假设入口时A(第一层),与A直接相连的岔口有B,C(第二层),然后开始探索B,和B直 接 相连的岔路口有D,E(第三次),与C直接相连的岔路口有F,G(第三层),探索完B后探索C,之后又开始探索E, F,G,H,…
对于广度优先遍历可以用队列实现
1.现在队列里放入起始点A,然后取队首元素A,将与A直接相连的岔口B,C入队,此时队里有{B,C}
2.队首元素B出队,和B直接相连的岔路口D,E入队对列里此时为{C,D,E},
3.队首元素出队,和B直接相连的岔路口F,G入队对列里此时为{D,E,F,G},
4.以此类推,逐层遍历。
基本模板如下:
void BFS(int s){
queue<int> q;
q.push(s);
while(!q.empty()){
取队首元素;
访问(输出)队首元素;
将队首元素出队;
将队首元素的下一层的节点中未曾入队的节点全部入队;
}
}
给定一个m*n的矩阵,矩阵中的元素为0或1,定义位置(x,y)的上,下,左,右,四个位置(x,y+1),(x,y-1),(x+1,y),(x-1,y),四个位置是相邻的,如果矩阵中有些1是相邻的,称他们构成了一个块,求给定矩阵中的快的个数
0111001
0010000
0000100
0001110
1110100
1111000
这个6*7矩阵的块数为4
#include<iostream>
#include<queue>
using namespace std;
const int maxn=100;
struct node{
int x,y;
}Node;
int n,m;
int store[maxn][maxn]; //存储每个位置的元素
bool inq[maxn][maxn]={false}; //标记元素是否入队过
int X[]={0,0,1,-1};
int Y[]={1,-1,0,0}; //定义四个位置
bool judge(int x,int y){ //判断该节点的元素是否需要访问
if(x>n||x<0||y>m||y<0)
return false;
if(inq[x][y]==true||store[x][y]==0)
return false;
return true;
}
void BFS(int x,int y){
queue<node> Q;
Node.x=x,Node.y=y;
Q.push(Node);
inq[x][y]=true; //标记该节点已入队
while(!Q.empty()){
node top=Q.front(); //取出该节点
Q.pop(); //弹出队首元素
for(int i=0;i<4;i++){ //遍历相邻四个元素,判断是否需要访问,
int newx=top.x+X[i];
int newy=top.y+Y[i];
if(judge(newx,newy)){
Node.x=newx;
Node.y=newy;
Q.push(Node);
inq[newx][newy]=true; //对入队的元素标记
}
}
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>store[i][j];
int sum=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(store[i][j]==1&&inq[i][j]==false){ //如果元素为1,且未被访问过
sum++;
BFS(i,j);
}
}
cout<<"sum is :"<<sum<<endl;
return 0;
}
一个类似的例子
给定一个nm的迷宫,其中“”代表不可穿越的墙壁,而“.”代表平地,S代表起点,T代表终点,从起点开始移动,只能向上下左右四个方向移动,求从起点到终点的最少步数。。。
。 。。 。 。
。 * 。 * 。
。 * S * 。
。 。 。 T *
S的坐标是[2,2],T的坐标是[3,4]
#include<iostream>
#include<queue>
using namespace std;
const int maxn=100;
struct node{
int x,y;
int step;
}S,T,Node;
int n,m;
char store[maxn][maxn];
bool inq[maxn][maxn]={false};
int X[]={0,0,1,-1};
int Y[]={1,-1,0,0};
bool judge(int x,int y){
if(x>n||x<0||y>m||y<0)
return false;
if(inq[x][y]==true||store[x][y]=='*')
return false;
return true;
}
int BFS(){
queue<node> Q;
Q.push(S);
inq[S.x][S.y]=true;
while(!Q.empty()){
node top=Q.front();
Q.pop();
if(top.x==T.x&&top.y==T.y)
return top.step; //找到出口
for(int i=0;i<4;i++){
int newx=top.x+X[i];
int newy=top.y+Y[i];
if(judge(newx,newy)){
Node.x=newx;
Node.y=newy;
Node.step=top.step+1;
Q.push(Node);
inq[newx][newy]=true;
}
}
}
return -1; //未找到出口
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>store[i][j];
cout<<"start x,y and end x,y"<<endl;
cin>>S.x>>S.y>>T.x>>T.y;
cout<<"sum is :"<<BFS()<<endl;
return 0;
}
注意当使用STL的queue时,元素入队的push()操作,只是制造了该元素的副本入队,因此,在队列里对该该元素的修改不会影响到原来的元素,对原来元素的修改也不会影响到副本元素。如下面的例子:
#include<iostream>
#include<queue>
using namespace std;
struct node{
int data;
}a[10];
int main()
{
queue <node> Q;
for(int i=0;i<10;i++){
a[i].data=i;
Q.push(a[i]);
}
Q.front().data=100;
cout<<a[0].data<<" "<<Q.front().data<<" ";
Q.pop();
a[1].data=20;
cout<<a[1].data<<" "<<Q.front().data;
return 0;
} //结果时0 100 20 1
如果在元素在队列里时要修改元素,而不是访问它,此时可以把他的序号入队,而不是元素本身,修改上面的代码如下:
#include<iostream>
#include<queue>
using namespace std;
struct node{
int data;
}a[10];
int main()
{
queue <int> Q;
for(int i=0;i<10;i++){
a[i].data=i;
Q.push(i);
}
a[Q.front()].data=100;
cout<<a[0].data<<" "<<a[Q.front()].data<<" ";
Q.pop();
a[1].data=20;
cout<<a[1].data<<" "<<a[Q.front()].data;
return 0;
} //结果为100 100 20 20