广度优先搜索(BFS)

引入

如果说深度优先搜索是“不撞南墙不回头”,那么广度优先搜索就是“剥洋葱”。
因为洋葱是一层一层的。

算法模板

这个从树的角度来看,就是层次遍历(一层一层的,从上到下,从左到右)

创建一个队列
先将根节点入队
while(队列非空){
获取头结点;
访问头结点;
头结点出队;
基于当前的结点,遍历所有与之相邻,且未入队的所有结点,将其入队
}

这个需要注意是将所有“未入队”的结点入队,而非“未访问”。
未入队,就是从来没进过队列
未访问,则包含了已经进队,当时还没排到访问(会重复入队)

例子

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

Sample Input:

6 7
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

Sample Output:

4

思路:

对于矩阵 Matrix[m][n] 遍历每个元素,如果为0,则跳过;如果为 1 ,则使用BFS查询与该位置相邻的4个位置(前提是不出界),判断它们是否为 1(如果相邻的位置为1,则同样去查询与该位置相邻的4个位置,直到整个“1”块访问完毕)。为了防止走回头路,设置一个 bool型的 inq数组记录 每个元素是否已被访问过(在BFS中入队)。

技巧:

对于当前元素的下一层:上下左右,可以用增量数组访问,设置2个增量数组,来表示4个方向。

int X[] = {-1, 1, 0, 0}; // 上下左右
int Y[] = {0, 0, -1, 1};

代码

#include<stdio.h>
#include<queue>
using namespace std;
const int maxn = 100;
int m,n;//m行n列
int mar[maxn][maxn];

struct Node {
	int x;
	int y;
} node;
//标记四个方向
int X[4] = {0,0,-1,1};
int Y[4] = {1,-1,0,0};
//是否入队判断
bool inq[maxn][maxn] = {false};
bool judge(int x,int y) {
	if(x<=0||x>m||y<=0||y>n)//越界判断
		return false;
	if(inq[x][y] == true||mar[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);
	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() {
	scanf("%d %d",&m,&n);
	for(int i = 1; i<=m; i++)
		for(int j = 1; j<=n; j++)
			scanf("%d",&mar[i][j]);
	int ans = 0;
	for(int i = 1; i<=m; i++)
		for(int j = 1; j<=n; j++) {
			if(inq[i][j] == false && mar[i][j] == 1) {
				ans++;
				BFS(i,j);
			}
		}
	printf("%d\n",ans);
	return 0;
}

posted @ 2021-03-10 10:59  我就是隔壁老张  阅读(127)  评论(0编辑  收藏  举报