浅谈BFS模板思路(一)

哈喽!这里是一只派大鑫,不是派大星。本着基础不牢,地动山摇的学习态度,从基础的C语言语法讲到算法再到更高级的语法及框架的学习。更好地让同样热爱编程(或是应付期末考试 狗头.jpg)的大家能够在学习阶段找到好的方法、路线,让天下没有难学的程序(只有秃头的程序员 2333),学会程序和算法,走遍天下都不怕!

前言: 

 来讲一下广度优先搜索BFS对应的题目里的使用模板,以及详细的解题思路过程,并给出一道经典案例来进行补充说明,最后给出解题代码收尾,相信你读完之后一定会有收获的!

广搜模板:

广度优先搜索一般由队列实现,且总是按层次的顺序进行遍历,其基本写法如下(可作模板用):

void BFS(int s){
	queue<int> q;
	q.push(s);
	while(!q.empty()){
		取出队首元素top;
		访问队首元素top;
		将队首元素出队;
		将top的下一层结点中未曾入队的结点全部入队,并设置为已入队
	}
}

模板解读:

 下面是对该模板中每一个步骤的说明,请结合代码一起看:

①定义队列q,并将起点s入队。

②写一个while循环,循环条件是队列q非空。

③在while循环中,先取出队首元素top,然后访问它(访问可以是任何事情,例如将其输出)。访问完后将其出队。

④将top的下一层结点未曾入队的结点入队,并标记它们的层号为now的层号+1,同时设置这些入队的结点已入过队。

⑤返回②继续循环。

 举个栗子:

下面举一个例子,希望读者能从中学习BFS的思想是如何通过队列来实现的,并能尝试学习写出本例的代码。

给出一个m×n的矩阵,矩阵中的元素为0或1。称位置(x,y)与其上下左右四个位置:(x,y+1)、(x,y-1)、(x+1,y)、(x-1,y)是相邻的。如果矩阵中有若干个1是相邻的(不必两两相邻),那么称这些1构成了一个“块”。求给定的矩阵中“块”的个数。

                                  0 1 1 1 0 0 1
                                  0 0 1 0 0 0 0
                                  0 0 0 0 1 0 0
                                  0 0 0 1 1 1 0
                                  1 1 1 0 1 0 0
                                  1 1 1 1 0 0 0

例如上面的6×7的矩阵中,“块”的个数为4。

分析栗子:

 对这个问题,求解的基本思想是:

枚举每一个位置的元素,如果为0,则跳过;

如果为1,则使用BFS查询与该位置相邻的4个位置(前提是不出界),

判断它们是狗为1(如果某个相邻的位置为1,则同样去查询与该位置相邻的4个位置,知道整个“1”块访问完毕)。

而为了防止走回头路,一般可以设置一个bool型数组inq(即in queue的简写)来记录每个位置是否在BFS中已入过队。

一个小技巧是:        对当前位置(x,y)来说,由于与其相邻的四个位置分别为(x,y+1)、(x,y-1)、(x+1,y)、(x-1,y),那么不妨设置下面这两个增量数组,来表示四个方向(竖着看即为四个方向)。

int x[] = {0,0,1,-1};

int y[] = {1,-1,0,0};

这样就可以使用for循环来枚举4个方向,以确定与当前坐标(nowX,nowY)相邻的4个位置,如下所示:

for(int i = 0; i < 4; i++){
	newX = nowX + x[i];
	newY = nowY + Y[i];
}

解题代码:

 下面给出本例的代码,希望读者能仔细理解代码中BFS的写法,并在之后尝试自己独立重写(请读者也用DFS实现本题):

#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;

const int maxn = 100;
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};

bool judge(int x,int 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 false;
	//以上都不是,则返回true
	return true;
}
//BFS函数访问位置(x,y)所在的块,将该块中所有“1”的inq都设置为true
void BFS(int x,int y){
	queue<node> q;              //定义一个队列
	Node.x = x, Node.y = y;    //当前结点的坐标为(x,y)
	q.push(Node);    //将结点Node入队
	inq[x][y] = true;
	while(!q.empty()){
		node top = q.front();  //取出队首元素
		q.pop();               //队首元素出队
		for(int i = 0; i < 4; i++){    //循环4次,得到4个相邻位置
			int newX = top.x + X[i];
			int newY = top.y + Y[i];
			if(judge(newX,newY)){  //如果新位置(newX,newY)需要访问
				//设置Node的坐标为(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);
	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,且未入过队
			if(matrix[x][y] == 1 && inq[x][y] == false){
				ans++;   //块数+1
				BFS(x,y); //访问整个块,将该块所有“1”的inq都标记为true
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}

至此,这篇文章就讲完了,如果你觉得对你有帮助,不妨三连点赞收藏加关注,学习知识不迷路

猜你喜欢

转载自blog.csdn.net/weixin_44572229/article/details/121304289