欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

相关标签: 深度优先遍历