博客
关于我
判断矩阵块的数目(广度优先搜索)
阅读量:363 次
发布时间:2019-03-04

本文共 3727 字,大约阅读时间需要 12 分钟。

1. 问题描述:

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

例如下面的例子6 * 7的矩阵中,块的数目是4:

0 1 1 1 0 0 10 0 1 0 0 0 00 0 0 0 1 0 0 0 0 0 1 1 1 01 1 1 0 1 0 0 1 1 1 1 0 0 0

2. 思路分析:

① 对于这类问题而言非常经典,实质上是检测联通块的数目,可以使用深度优先搜索来解决,从矩阵的起始顶点出发,深度优先搜索每一个没有被访问过的顶点,而且当前的元素必须是1的时候才能够往下进行访问,对于当前的顶点是否被访问我们需要使用一个标记数组来进行标记,然后进行深度优先搜索遍历,对于这道题目而言我们可以在访问的时候将其1位置的元素值变为0那么就不用再使用标记数组来进行标记了,每一次搜索结束的时候那么联通块的数目就加1,最终搜索完成之后那么就可以得到整个矩阵中联通块的数目了

② 除了使用深度优先搜索之外,我们还可以使用广度优先搜索来解决,求解的基本思路如下:

枚举每一个位置上的元素,如果是0那么跳过,如果是1则使用bfs查询与该位置相邻的4个位置(前提使不出界)判断他们是否是1,如果某个相邻的位置是1那则同样去查询与该位置相邻的四个位置,直到1的块被访问完毕,为了防止重复访问顶点的问题,我们可以设置一个标记数组,可以是整型或者是布尔型数组来记录每个位置是否入过队列

这里需要注意的是判断当前的顶点是否入过队列,而不是当前的节点是否被访问过,我之前写的广度优先搜索的迷宫问题标记的是当前的顶点是否被访问过,这两个的区别在于:如果设置成是否已被访问,那么有可能某个顶点还在队列中(但是还未被访问)时由与其他顶点正在可以到达它而将这个顶点再次入队导致很多顶点反复入队,所以造成了重复计算的问题,因此bfs让每一个顶点都只入队一次,所以需要设置成标记数组的含义是顶点是否入过队而不是顶点是否被访问

③ 使用广搜的一个小技巧是对于当前位置的四个位置我们可以声明两个增量数组来表示四个方向,这样在检查当前位置的四个相邻的位置的时候可以使用for循环来进行检查判断

static int posx[] = {0, 0, 1, -1};static int posy[] = {1, -1, 0, 0};

④ 广搜的一般是借助于队列来实现,首先往队列中加入起始顶点然后再while循环中弹出队列中的一个节点,然后加入当前节点的若干个满足条件的邻居节点知道最后队列为空那么整个广度优先就结束了

3. 相关的代码如下:

Java代码:

import java.util.LinkedList;import java.util.Queue;import java.util.Scanner;public class Main {	static int arr[][];	static int inq[][];	static int n;	static int m;	static int posx[] = {0, 0, 1, -1};	static int posy[] = {1, -1, 0, 0};	public static void main(String[] args) {		Scanner sc = new Scanner(System.in);		//输入行数和列数		n = sc.nextInt();		m = sc.nextInt();		arr = new int[n][m];		inq = new int[n][m];		for(int i = 0; i < n; ++i){			for(int j = 0; j < m; ++j){				arr[i][j] = sc.nextInt();			}		}		int res = 0;		for(int i = 0; i < n; ++i){			for(int j = 0; j < m; ++j){				if(arr[i][j] == 1 && inq[i][j] == 0){					res++;					bfs(i, j);					}			}		}		System.out.println(res);		sc.close();	}		private static void bfs(int x, int y) {		Node p = new Node(x, y);		Queue
queue = new LinkedList
(); queue.add(p); inq[x][y] = 1; while(!queue.isEmpty()){ Node poll = queue.poll(); for(int i = 0; i < 4; ++i){ int newx = poll.x + posx[i]; int newy = poll.y + posy[i]; if(judge(newx, newy)){ Node newNode = new Node(newx, newy); queue.add(newNode); inq[newx][newy] = 1; } } } } private static boolean judge(int x, int y) { if(x >= n || x < 0 || y >= m || y < 0) return false; if(arr[x][y] == 0 || inq[x][y] == 1) return false; return true; } //封装节点类似于C与C++中的结构体 public static class Node{ int x; int y; public Node(int x, int y) { super(); this.x = x; this.y = y; } }}

C++代码:

#include
#include
#include
using namespace std;const int maxn = 100;struct node{ int x; int y;}Node;int n, m;int matrix[maxn][maxn];bool inq[maxn][maxn] = {false};int posx[4] = {0, 0, 1, -1};int posy[4] = {1, -1, 0, 0};bool judge(int x, int y){ if(x >= n || x < 0 || y >= m || y < 0) return false; if(matrix[x][y] == 0 || inq[x][y] == true) return false; return true;}void bfs(int x, int y){ queue
que; Node.x = x; Node.y = y; que.push(Node); inq[x][y] = true; while(!que.empty()){ node top = que.front(); que.pop(); //通过循环四次得到四个相邻的位置 for(int i = 0; i < 4; i++){ int newx = top.x + posx[i]; int newy = top.y + posy[i]; cout << newx << " " << newy << endl; if(judge(newx, newy)){ Node.x = newx; Node.y = newy; que.push(Node); inq[newx][newy] = true; } } }}int main(void){ cin >> n >> m; for(int i = 0; i < n; ++i){ for(int j = 0; j < m; ++j){ cin >> matrix[i][j]; } } int ans = 0; for(int i = 0; i < n; ++i){ for(int j = 0; j < m; ++j){ if(matrix[i][j] == 1 && inq[i][j] == false){ ans++; bfs(i, j); } } } cout << ans; return 0;}

 

转载地址:http://jrwg.baihongyu.com/

你可能感兴趣的文章
NIFI同步MySql数据_到SqlServer_错误_驱动程序无法通过使用安全套接字层(SSL)加密与SQL Server_Navicat连接SqlServer---大数据之Nifi工作笔记0047
查看>>
Nifi同步过程中报错create_time字段找不到_实际目标表和源表中没有这个字段---大数据之Nifi工作笔记0066
查看>>
NIFI大数据进阶_FlowFile拓扑_对FlowFile内容和属性的修改删除添加_介绍和描述_以及实际操作---大数据之Nifi工作笔记0023
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_处理器介绍_处理过程说明---大数据之Nifi工作笔记0019
查看>>
NIFI大数据进阶_Json内容转换为Hive支持的文本格式_操作方法说明_01_EvaluteJsonPath处理器---大数据之Nifi工作笔记0031
查看>>
NIFI大数据进阶_Kafka使用相关说明_实际操作Kafka消费者处理器_来消费kafka数据---大数据之Nifi工作笔记0037
查看>>
NIFI大数据进阶_Kafka使用相关说明_实际操作Kafka生产者---大数据之Nifi工作笔记0036
查看>>
NIFI大数据进阶_NIFI的模板和组的使用-介绍和实际操作_创建组_嵌套组_模板创建下载_导入---大数据之Nifi工作笔记0022
查看>>
NIFI大数据进阶_NIFI监控功能实际操作_Summary查看系统和处理器运行情况_viewDataProvenance查看_---大数据之Nifi工作笔记0026
查看>>
NIFI大数据进阶_NIFI监控的强大功能介绍_处理器面板_进程组面板_summary监控_data_provenance事件源---大数据之Nifi工作笔记0025
查看>>
NIFI大数据进阶_NIFI集群知识点_认识NIFI集群以及集群的组成部分---大数据之Nifi工作笔记0014
查看>>
NIFI大数据进阶_NIFI集群知识点_集群的断开_重连_退役_卸载_总结---大数据之Nifi工作笔记0018
查看>>
NIFI大数据进阶_内嵌ZK模式集群1_搭建过程说明---大数据之Nifi工作笔记0015
查看>>
NIFI大数据进阶_外部ZK模式集群1_实际操作搭建NIFI外部ZK模式集群---大数据之Nifi工作笔记0017
查看>>
NIFI大数据进阶_实时同步MySql的数据到Hive中去_可增量同步_实时监控MySql数据库变化_操作方法说明_01---大数据之Nifi工作笔记0033
查看>>
NIFI大数据进阶_离线同步MySql数据到HDFS_01_实际操作---大数据之Nifi工作笔记0029
查看>>
NIFI大数据进阶_离线同步MySql数据到HDFS_02_实际操作_splitjson处理器_puthdfs处理器_querydatabasetable处理器---大数据之Nifi工作笔记0030
查看>>
NIFI大数据进阶_离线同步MySql数据到HDFS_说明操作步骤---大数据之Nifi工作笔记0028
查看>>
NIFI大数据进阶_连接与关系_设置数据流负载均衡_设置背压_设置展现弯曲_介绍以及实际操作---大数据之Nifi工作笔记0027
查看>>
NIFI数据库同步_多表_特定表同时同步_实际操作_MySqlToMysql_可推广到其他数据库_Postgresql_Hbase_SqlServer等----大数据之Nifi工作笔记0053
查看>>