有这样一个题目

给出一个mxn的矩阵,矩阵中的元素为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
例如上面的6x7矩阵中,“块”的个数是4。

对于这个问题,基本思想是枚举每一个位置的元素,如果为1且未访问过(用一个二维bool数组标记是否访问过),说明这是个新“块”,块数增1,访问该位(置对应bool二维数组元素为true),并对其进行深度搜索或者广度搜索,即同样地查询与之相邻的四个位置,枚举和遍历都结束后输出块数即可。
为方便查询相邻的四个位置,可以建立两个增量数组,表示四个方向。
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};
竖着来看即(0,1)、(0,-1)、(1,0)、(-1,0)
这样就可以用for循环来枚举四个方向,以确定与当前坐标(nowX,nowY)相邻的4个位置,如下所示:

for(int i=0;i<4;i++){nowX=nowx+X[i];nowY=nowy+Y[i];}

广度遍历算法如下:

#include<cstdio>
const int maxn=100;
using namespace std;
int n,m;
int matrix[maxn][maxn];//0,1矩阵
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){//判断坐标(x,y)是否需要访问if(x<0||x>n||y<0||y>m)//越界,返回falsereturn false;//已经访问过或当前位为0,返回falseif(inq[x][y]==true||matrix[x][y]==0)return false;//除去以上情况,返回truereturn true;
}
void dfs(int x,int y){//深度遍历算法if(!judge(x,y)) return ;//递归出口,当前位不需要访问inq[x][y]=true;//置访问位为truefor(int i=0;i<4;i++){//查询相邻的位置dfs(x+X[i],y+Y[i]);}
}
int main(){scanf("%d%d",&m,&n);//输入行列for(int i=0;i<m;i++){//输入矩阵for(int j=0;j<n;j++){scanf("%d",&matrix[i][j]);}}int ans=0;//块数for(int i=0;i<m;i++){for(int j=0;j<n;j++){//枚举每一位置if(matrix[i][j]==1&&inq[i][j]==false){//当前位为1且未访问//说明找到新"块"ans++;dfs(i,j);}}}printf("%d",ans);return 0;
}

这道题也可以用广度遍历算法来做,广度遍历算法需用到队列,枚举思想同上,如遇到为1且未访问的位,说明是新块,块数要加1,还要将这块中的所有元素都访问。广度遍历的做法是将当前位入队,访问队首元素并出队,然后将与队首相邻的需要访问的位入队,此后不断地进行出队入队操作,直到队空为止,说明本块中全部访问完了。最后输出块数。
算法只有BFS部分不同,代码如下:

#include<cstdio>
#include<queue>
const int maxn=100;
using namespace std;
int n,m;
int matrix[maxn][maxn];
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};
bool inq[maxn][maxn]={false};
struct node{int x,y;
}Node;
queue<node> q;
bool judge(int x,int y){if(x<0||x>n||y<0||y>m)return false;if(inq[x][y]==true||matrix[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);//将该结点入队列inq[x][y]=true;//设置该结点已经入过队while(!q.empty()){//队空即结束node top=q.front();//取队首结点q.pop();//将队首结点出队for(int i=0;i<4;i++){//访问相邻位置int nowX=top.x+X[i];int nowY=top.y+Y[i];if(judge(nowX,nowY)){//如果该位置需要访问Node.x=nowX;//设置Node坐标Node.y=nowY;q.push(Node);//将结点入队inq[Node.x][Node.y]=true;//设置该结点已入过队}}}}
int main(){scanf("%d%d",&m,&n);for(int i=0;i<m;i++){for(int j=0;j<n;j++){scanf("%d",&matrix[i][j]);}}int ans=0;for(int i=0;i<m;i++){for(int j=0;j<n;j++){if(matrix[i][j]==1&&inq[i][j]==false){ans++;bfs(i,j);}}}printf("%d",ans);return 0;
}

最后再提醒一下,BFS中设置的inq数组的含义是判断结点是否入队,而不是是否访问过,如果含义为是否访问,考虑这种情形:当前结点已在队中,但还未访问,故inq的相应位不会置为true,此时被其他与其相邻的结点查询到,从而导致其重复入队,计算量大增。
还有一点就是STL的 queue的push操作只是制造了一个该元素的一个副本入队,因此在入队后对原元素的访问不会影响队中的副本,对队中副本的修改也不会改变原元素,这点和传递指针是相反的。

求矩阵的连通分支数问题相关推荐

  1. 牛客-计算机复试题-求图的连通分支数

    求图的连通分支数可以用并查集实现. 并查集的讲解推荐: https://blog.csdn.net/liujian20150808/article/details/50848646 本题求的是无向图的 ...

  2. DFS求图的连通分支、割点数、判断是否连通

    连通分支数 /*DFS求图的连通分支数 */ #include <stdio.h> #define N 1 //看是否所有顶点都被访问标记过 int IsVisit(int visit[] ...

  3. 无向图的连通分支数(并查集)

    目录 这是牛客网上题号为 KY268 的一道题 题目描述:该题的目的是要你统计图的连通分支数. 输入描述:每个输入文件包含若干行,每行两个整数 i, j,表示节点 i 和 j 之间存在一条边. 输出描 ...

  4. C语言求矩阵的逆(伴随法)

    之前介绍了C语言用代数余子式求行列式 本次开始介绍如何用公式法对矩阵求逆,并用C语言将其实现. 之前程序有点小bug,已于2022年11月29日修改. 目录 数学原理 矩阵求逆的公式 数乘矩阵 程序设 ...

  5. 2013吉林通化邀请赛 1004 D-City 并查集求连通分支数

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4496 将题目要查询的数倒过来求,先加一条边,保存cc(连通分支数)  然后再加一条边.... 当合并两 ...

  6. 首先从键盘上两个矩阵的行数n和列数m,然后输入两个矩阵A和B的元素值,最后求出两个矩阵的和C并输出其元素值。

    输入格式: 第1行包含两个整数n和m,表示矩阵的行数和列数. 接下来n行,每行m个整数,表示矩阵A的元素值. 再接下来n行,每行m个整数,表示矩阵B的元素值. 相邻两个整数之间用空格分隔. 输出格式: ...

  7. matlab求矩阵均值向量,如何求一个矩阵的均值向量

    四.线性方程组 考试内容 线性方程组的克莱姆(Cramer)法则 线性方程组有解和无解的判定齐次线性方程组的基础解系和通解非齐次线性方程组的解与相应的齐次线性方程组(导出组)的解之间的关系非齐次线性方 ...

  8. HDU 4587 TWO NODES(割两个点的最大连通分支数)

    http://acm.hdu.edu.cn/showproblem.php?pid=4587 题意: 给一图,求割去两个点后所能形成的最大连通分支数. 思路: 对于这种情况,第一个只能枚举,然后在删除 ...

  9. Java黑皮书课后题第8章:*8.1(求矩阵中各列数字的和)使用下面的方法头编写一个方法,求矩阵中特定列的所有元素的和。编写一个测试程序,读取3*4矩阵,显示每列元素的和

    *8.1(求矩阵中各列数字的和)使用下面的方法头编写一个方法,求矩阵中特定列的所有元素的和.编写一个测试程序,读取3*4矩阵,显示每列元素的和 题目 题目描述与运行示例 破题 代码 题目 题目描述与运 ...

最新文章

  1. java并发处理时mvel表达式处理慢,一文说清!
  2. ios上架图片在线制作_TF上架是什么?上架testflight真的不掉签吗?
  3. 虚拟网络的组建和应用课后习题答案
  4. 【Python数据分析】魔术命令(Magic Command)
  5. hhkb mac设置_把 HHKB 放在 MacBook 上使用的解决方案
  6. (转) Dockerfile 中的 COPY 与 ADD 命令
  7. linux下图片加密原理,Linux中常见的加密技术介绍
  8. 掌握了AI这些点,面试官的天选之子就是你
  9. oracle linux 版本 uek,在运行 Oracle Linux 7.1 UEK3 或 7.2 或者 RHEL 7.1 或 7.2 的系统上,RDMA 服务无法启动...
  10. mysql报错:Host ***.***.***.*** is not allowed to connect to this MySQL server
  11. ubuntu16.04中安装MESA 17.3.3
  12. SVN安装和中文语言包安装
  13. Linux 服务器上安装 ANSYS Fluent 2020R2
  14. 如何用计算机计算一元三次方程,计算器如何解一元三次方程?
  15. python怎么下载numpy?
  16. 【译】网页像素追踪原理
  17. ios 制作方形头像
  18. JAVA中输出分两栏,老司机搞定Java 设置Word分栏
  19. 2. Hibernate目录结构和基础JAR包介绍
  20. 安装RedHat Linux 7.4

热门文章

  1. 安卓实现ExpandableList中子项不同的布局
  2. LR(1)文法智能分析
  3. 新版ASTM D4169-22标准解读
  4. 使用谷歌地图 Javascript版
  5. tftp下载目录设置
  6. 山工kw什么意思_为什么有时开了空调,反而感觉车子动力会变强
  7. Errors during downloading metadata for repository ‘docker-ce-stable‘
  8. java要cpu_排查CPU占用过高的问题
  9. filter / map 基础学习
  10. GPIO的初始化程序