1、BFS计算连通域个数
// https://blog.csdn.net/weixin_41788963/article/details/104470487
//【算法笔记】基于广度优先搜索(BFS)求解图像连通域
//简介
//广度优先搜索,是以广度作为第一关键词,当碰到岔口时,首先访问这个岔口能直接到达的所有结点,然后这些结点被访问的顺序,依次继续访问其可以到达的所有结点,直到所有结点都被访问,或者满足终止条件;
//
//算法较为理想的实现方式是使用队列,将前面的元素不断弹出,在搜索过程中,将下一层的元素不断地补在后面,直到队列为空,或是满足条件,完成搜索;
//
//完成demo后,发现本方法适用于求取图像中的连通域个数、大小、排序等,因此作为扩展,在此记录求解连通域的用法;
//————————————————
//版权声明:本文为CSDN博主「Henry爱学习」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
//原文链接:https://blog.csdn.net/weixin_41788963/article/details/104470487
//模板
//void BFS(int s){
// queue<int> q;
// q.push(s);
// while(!q.empty()){
// 取出队首元素top;
// 访问队首元素top;
// 将队首元素出队;
// 将top的下一层结点中,未曾入队的全部入队;
// }
//}
//对于上述模板的说明如下:
//
//1.定义队列 q,并将起点 s 入队;
//2.定义 while 循环,循环条件是 q 非空;
//3.在 while 循环中,先取出队首的元素 top,然后访问 top,访问结束后令 top 出队;
//4.将 top下一层结点中未曾入队的结点全部入队,如果需要记录层号,此时层号加一,同时设置上述结点已经入过队;
//5.返回步骤 2,直到队列为空或满足其他终止条件;
//Demo
//给出一个 m×n 的矩阵,矩阵中的元素为0或1(与二值图像等效),定义位置 (x,y) 与其上下左右四个位置 (x-1, y), (x+1, y), (x, y-1), (x, y+1)
//是相邻的。由相邻的点连成的区域就叫连通域,求给定矩阵中连通域的个数,给出 6×7 的矩阵示例如下,首行输入尺寸,随后输入矩阵的值:
//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
//问题分析
//1.枚举每一个位置的元素,如果为 0,跳过;如果为 1,则使用 BFS 查询邻近的 4 个元素(保证不出界,且不重复访问), 判断其是否为 1,循环往复,知道一个连通域内的 1 全部访问;
//2.为了防止走“回头路”,防止重复访问同一个 1,设置一个 bool 型的数组 inq(意为in queue) 来记录每个 1 是否在 BFS 中已经入过队;
//3.设置两个数组来表示 4 个方向,用 for 循环省略了 4 个 if;
//int row[4] = {0, 0, 1, -1};
//int col[4] = {1, -1, 0, 0};
//for(int i=0;i<4;i++){
// new_x = x + row[i]; //x, y 分别是当前位置的行和列
// new_y = y + col[i];
// ...
//}
//代码
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn = 30; //假设矩阵最大的尺寸是 30×30
// 定义Node 变量来记录(x,y) 坐标
struct Node{
int x, y;
};
int matrix[maxn][maxn]; //定义输入矩阵
int m, n; //定义矩阵的行和列
bool inq[maxn] [maxn] = {false}; //定义查询矩阵
int row[4] = {1, -1, 0, 0};
int col[4] = {0, 0, 1, -1}; // 定义访问上下左右四个方向的变量
queue<Node> a; // 定义记录搜索过程的队列
// 定义判断函数,判断某点是否值为1,没有超出尺寸,且没有被访问过
bool judge(int x, int y) {
if(x<0 || x>=m || y<0 || y>=n) return false;
if(matrix[x][y]==0 || inq[x][y]==true) return false;
return true;
}
void BFS(int x, int y){
Node p, temp; // 定义p为当前位置, temp为临近的四个位置
p.x = x;
p.y = y;
a.push(p); //访问并入队
inq[x] [y]=true; //更新访问状态
while(!a.empty()){
p = a.front(); // 令P访问a的队首作为当前节点
a.pop(); //弹出a的队首
//访问临近节点,符合条件的入队,直到队列a为空
for(int i=0; i<4; i++) {
int new_x = p.x + row[i];
int new_y = p.y + col[i];
if(judge(new_x, new_y)==true){
temp.x = new_x;
temp.y = new_y;
a.push(temp);
inq[new_x][new_y] = true;
}
}
}
}
int main(){
printf("Please input the row and column:\n");
// 矩阵维度
// scanf("%d%d", &m, &n);
m = 6;
n = 7;
printf("Please input matrix:\n");
// 输入矩阵
int mat[42]={
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,};
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
// scanf("%d", &matrix[i][j]);
matrix[i][j] = mat[i*n+j];
}
}
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
printf("%d", matrix[i][j]);
}
printf("\n");
}
//ans 记录连通域个数
int ans=0;
for(int i=0; i<m; i++) {
for(int j=0; j<n; j++){
//符合条件的点进入BFS
if(matrix[i][j]==1 && inq[i][j]==false) {
ans++;
BFS(i,j);
}
}
}
printf("%d\n", ans);
getchar();
return 0;
}
2、 BFS标记连通域
//代码
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn = 30; //假设矩阵最大的尺寸是 30×30
int ans=0;
// 定义Node 变量来记录(x,y) 坐标
struct Node{
int x, y;
};
int matrix[maxn][maxn]; //定义输入矩阵
int m, n; //定义矩阵的行和列
//bool inq[maxn] [maxn] = {false}; //定义查询矩阵
int inq[maxn] [maxn] = {0}; //定义查询矩阵
int row[4] = {1, -1, 0, 0};
int col[4] = {0, 0, 1, -1}; // 定义访问上下左右四个方向的变量
queue<Node> a; // 定义记录搜索过程的队列
// 定义判断函数,判断某点是否值为1,没有超出尺寸,且没有被访问过
bool judge(int x, int y) {
if(x<0 || x>=m || y<0 || y>=n) return false;
if(matrix[x][y]==0 || inq[x][y]>0) return false;
return true;
}
void BFS(int x, int y){
Node p, temp; // 定义p为当前位置, temp为临近的四个位置
p.x = x;
p.y = y;
a.push(p); //访问并入队
inq[x] [y]=ans; //更新访问状态
while(!a.empty()){
p = a.front(); // 令P访问a的队首作为当前节点
a.pop(); //弹出a的队首
//访问临近节点,符合条件的入队,直到队列a为空
for(int i=0; i<4; i++) {
int new_x = p.x + row[i];
int new_y = p.y + col[i];
if(judge(new_x, new_y)==true){
temp.x = new_x;
temp.y = new_y;
a.push(temp);
inq[new_x][new_y] = ans;
}
}
}
}
int main(){
printf("Please input the row and column:\n");
// 矩阵维度
// scanf("%d%d", &m, &n);
m = 6;
n = 7;
printf("rows: %d\n", m);
printf("cols: %d\n", n);
printf("Please input matrix:\n");
// 输入矩阵
int mat[42]={
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,};
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
// scanf("%d", &matrix[i][j]);
matrix[i][j] = mat[i*n+j];
}
}
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
printf("%d", matrix[i][j]);
}
printf("\n");
}
//ans 记录连通域个数
for(int i=0; i<m; i++) {
for(int j=0; j<n; j++){
//符合条件的点进入BFS
if(matrix[i][j]==1 && inq[i][j]==0) {
ans++;
BFS(i,j);
}
}
}
printf("connection regions: %d\n", ans);
printf("labeled matrix:\n");
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
printf("%d", inq[i][j]);
}
printf("\n");
}
getchar();
return 0;
}
输出结果:
Please input the row and column:
rows: 6
cols: 7
Please input matrix:
0111001
0010000
0000100
0001110
1110100
1111000
connection regions: 4
labeled matrix:
0111002
0010000
0000300
0003330
4440300
4444000