BFS 层序遍历 晴天模板大放送

2 篇文章 0 订阅
<span style="font-size:24px;"><strong>第一个例子:计算二维字符数组的块数,1表示有效,0表示无效</strong></span>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=1010;
struct node{
	int x,y;//位置(x,y) 
}Node;

int n,m;//矩阵大小为n*m 

int matrix[maxn][maxn];//01矩阵 
bool inq[maxn][maxn]={false};//记录位置(x,y)是否已经入过队 
int X[4]={0,0,1,-1};//增量数组
int Y[4]={1,-1,0,0};//两个增量数组可以表示方向 


//在一次BFS判断该结点是否需要访问的函数
//如果这个点越过了边界,或这个点是0,或这个点已经入过队了,(在那次入队将必定会进行遍历),就返回false,表示这个点无需再访问
//如果这个点是1且没有入过队,就说明要访问! 
bool judge(int x,int y){//判断坐标(x,y)是否需要访问 
	//越界返回false
	if(x>=n||x<0||y>=m||y<0) return false;
	//当前位置为0或者(x,y)已经入过队,返回false
	if(matrix[x][y]==0||inq[x][y]==true) return true;//如果当前元素为0或者当前元素已经入过队,也置为0
	//以上都不满足,返回true
	return true;	 
} 
//是在BFS中用到judge() 
//BFS函数访问位置(x,y)所在的块,并进行扩展,这个BFS需要参数的,将该块中所有的1的inq都置为true,并且入队 
void BFS(int x,int y){//调用到这个函数的时候当前点必须是1 
	queue<node> Q;//定义队列 
	Node.x=x;Node.y=y;//当前结点的坐标为(x,y)
	Q.push(Node);//将结点Node入队
	while(!Q.empty()){//这个循环将扩张出一个块 
		node top=Q.front();//取出队首元素
		Q.pop();//队首元素出队
		for(int i=0;i<4;i++){//循环4次,看一下四个相邻点的情况.这里用到了增量数组 
			int newX=top.x+X[i]; 
			int newY=top.y+Y[i];
			if(judge(newX,newY)){//如果新位置(newX,newY)需要访问。这用到judge,应该是判断在本次BFS有一些重复遍历到的已经入队的点。恩是这样的 
				//设置Node的坐标wei(newX,newY)需要访问
				Node.x=newX,Node.y=newY;
				Q.push(Node);//将结点Node加入队列
				inq[newX][newY]=true;//设置位置(newX,newY)已入过队列 
			} 
		} 
	} 
} 

int main(){
	scanf("%d%d",&n,&m);//n行m列的矩阵
	//读入矩阵 
	for(int x=0;x<n;x++){
		for(int y=0;y<m;y++){
			scanf("%d",&matrix[x][y]);
		}
	}
	 int ans=0;//存放块数
	 //注意是枚举每一个位置 
	 for(int x=0;x<n;x++){//这个地方是不需要考虑边界的,边界问题留给每一个点的时候查看相邻结点考虑 
	 	for(int y=0;y<m;y++){
	 		//如果元素为1,且未入过队。注意,如果入过队,必定已经属于某一个块了,那个块必定已经BFS遍历完成了。所以没有必要做重复功
			 if(matrix[x][y]==1&&inq[x][y]==false){//这里如果已经入过队说明这个点所在的块已经被完成了 
			 	ans++;//表示块数会增加1。因为遇到了一个不属于任何已发现的块的一个1,无论其是否孤立,都是一个新的块
				BFS(x,y);//访问整个块,将该块所有1的inq都标记为true,而且要入队等等 
			 } 
		 }
	 } 
	return 0;
}

第二个例子:计算从起点到终点的最小步数

//这题是字符型矩阵,必须过滤掉每行后面的换行符! 
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

const int maxn=100;
struct node{
	int x,y;
	int step;//step表示从起点S到达该位置的最小步数(即层数) 
}Node,S,T;//S为起点,T为终点 

int n,m;//n为行,m为列
char maze[maxn][maxn];//将存储迷宫信息 
bool inq[maxn][maxn]={false};//记录位置(x,y)是否已经入过队
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};

//检验位置(x,y)是否有效
bool judge(int x,int y){
	if(x>=n||y>=n||x<0||y<0)return false;
	if(maze[x][y]='*'||inq[x][y]==true) return false;//如果是墙壁或者已经入过队,这个点也不用访问了!
	return true; 
} 

int BFS(){//这个不需要参数因为只有一个起点 
	queue<node> q;//定义队列
	q.push(S);//先将起点S入列
	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++){//循环四次得到4个临近点 
			int newX=top.x+X[i];
			int newY=top.y+Y[i];
			if(judge(newX,newY)){//位置(newX,newY)有效,怎样有效是看是否是边界,是否是平地,是否不曾入队过(因为如果入队了的话,后面必将) 
				//设置Node的坐标
				Node.x=newX,Node.y=newY;
				Node.step=top.step+1;//Node层数为top的层数加1
				q.push(Node);//入队,层数加1
				inq[newX][newY]=true;//标记(newX,newY)已经加入队列 
			} 
		} 
	}
	return -1;//无法到达终点T时返回-1 
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		getchar();//必须过滤掉每行后面的换行符!
		for(int j=0;j<m;j++){
			maze[i][j]=getchar(); 
		}
		maze[i][m+1]='\0';//这里不太懂,有必要吗 
	}
	scanf("%d%d%d%d",&S.x,&S.y,&T.x,&T.y);
	S.step=0;//初始化起点的层数为0,即S到S的最下步数为0
	printf("%d\n",BFS()); 
	return 0;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值