一、问题描述
给出一个m×n的 矩阵,矩阵中的元素为0或1.称位置(x,y)与其上下左右四个位置(x,y+1)、(x,y-1)、(x+1,y)、(x-1,y)是相邻的。如果矩阵中又若干个1是相邻的(不必两两相邻),那么称这些1构成了一个“块”。求给定的矩阵中“块”的个数。
二、输入
针对每组测试数据,第1行是两个数n和m,接下来是m行n列由1和0组成的数据。
三、输出
给定矩阵“块”的个数
四、样例输入
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
五、样例输出
4
思路
该题是《算法笔记》广度优先搜索BFS专题例题,书中已给出思路,记录下来以便复习。
从第一个元素开始遍历矩阵,碰到第一个1,就令计数器ans加1,然后进行广度优先搜索,来把这个1所处的块里的1的inq都变成true,记录这些位置已入过队,当遍历达到该点且矩阵元素为1时,因为已入过队,所以ans不会加1。
代码
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 100;
/*
思路:从第一个元素开始遍历矩阵,碰到第一个1,就令计数器ans加1,然后进行广度优先搜索,
来把这个1所处的块里的1的inq都变成true,记录这些位置已入过队,当遍历达到该点且
矩阵元素为1时,因为已入过队,所以ans不会加1
*/
struct node
{
int x, y;
} Node;
int n, m; //矩阵大小为 n * m
int matrix[maxn][maxn]; //0,1矩阵
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) //判断坐标(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 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; //设置(x,y)入过队
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))
{ //如果新位置需要访问
//设置Node的坐标为(newX,newY)
Node.x = newX, Node.y = newY;
Q.push(Node); //将结点Node入队
inq[newX][newY] = true; //设置位置(newX,newY)已入过队
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> matrix[i][j]; //读入01矩阵
}
}
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
}
}
}
cout << ans << endl;
return 0;
}