哈喽!这里是一只派大鑫,不是派大星。本着基础不牢,地动山摇的学习态度,从基础的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;
}
至此,这篇文章就讲完了,如果你觉得对你有帮助,不妨三连点赞收藏加关注,学习知识不迷路