P1451 求细胞数量——最大联通块问题(DFS&BFS双解)

链接: 原题链接

题目描述

一矩形阵列由数字 0 到 9 组成,数字 1 到 9 代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。

输入格式

第一行两个整数代表矩阵大小 n 和 m。
接下来 n 行,每行一个长度为 m 的只含字符 0 到 9 的字符串,代表这个n×m 的矩阵。

输出格式

一行一个整数代表细胞个数。

输入输出样例
输入 #1复制
4 10
0234500067
1034560500
2045600671
0000000089
输出 #1复制
4

说明/提示

数据规模与约定
对于100% 的数据,保证 1 ≤ n,m ≤ 100 。

思路讲解

本题是典型的最大联通块问题。
注意:
1.要找到细胞块,当一个细胞块被 0 围住 的时候,这个就算是一个细胞块。
2.细胞块只能是 上下左右 ,斜角是无用的。

操作之前有一个问题,就是输入的是字符串,需要的是数字,那么如何把字符串变为数字?
可以用下面两种操作:

for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) 
			scanf("%1d",&a[i][j]);    // %1d 表示只读一位
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			char c;
			scanf("%c",&c);
			a[i][j]=c-'0';
		}
		getchar(); //注意吞掉换行符
	}  
DFS:

首先我们要确定从哪里开始遍历,如果从a[1][1]开始一个一个遍历的话,就会做很多的无用功,为什么呢?因为 a[1][1]可能就不是一个细胞从这里开始往下遍历是没有意义的。因此我们在DFS 前先加入一个判断:a [ i ][ j ] != 0&&v [ i ][ j ]!=1 来保证开始遍历的点一定未被访问过的细胞。
然后就是DFS部分了。用 x , y 表示当前已经访问的位置。用方向数组判断上下左右是否为细胞且是否被访问,如果是细胞且未被访问就进一步DFS了,如果不是细胞且已经被访问就不用再DFS。这里注意边界!
下面附上DFS代码:

//DFS
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1005;
int n,m;
int a[MAXN][MAXN];
int v[MAXN][MAXN];
int ans=0;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
void DFS(int x,int y)
{
	v[x][y]=1;
	for(int i=0;i<=3;i++)
	{
		int tx=x+dx[i];
		int ty=y+dy[i];
		if(!(tx>=1&&tx<=n&&ty>=1&&ty<=m))
			continue;
		if(a[tx][ty]==0||v[tx][ty]==1)
			continue;
		DFS(tx,ty);
	}	
}
int main()
{
	scanf("%d%d",&n,&m);
	memset(a,0,sizeof(a));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) 
			scanf("%1d",&a[i][j]); 		
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]!=0&&v[i][j]!=1)
			{
				DFS(i,j);
				ans++;
			}	
		}
	printf("%d",ans);
}
BFS:

BFS要用到队列,其他思路细节都与DFS差不多。
首先我们定义一个结构体,储存第一个入队元素和每一次入队元素,分别用 start 和 temp 表示。再申请一个队列,然后将第一个元素入队,如果队列不为空,将队首元素的相邻结点入队,队首元素出队,直至队列为空,一个最大联通块即找到,ans++。注意别忘记标记已经访问过的a [ i ][ j ]!
下面附上BFS代码:

//BFS 
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1005;
int n,m;
int a[MAXN][MAXN];
int v[MAXN][MAXN];
int ans=0;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
struct node{
	int x,y;
}start,temp;
queue<node>r;
void BFS(int x,int y); //表示从当前位置开始搜 
int main()
{
	scanf("%d%d",&n,&m);
	memset(a,0,sizeof(a));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) 
			scanf("%1d",&a[i][j]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]!=0&&v[i][j]!=1)
			{
				BFS(i,j);
				ans++;
			}
		}
	}
	printf("%d",ans);
} 
void BFS(int x,int y)
{
	start.x=x;			
	start.y=y;
	v[x][y]=1;
	r.push(start);
	while(!r.empty())
	{
		int nx=r.front().x;
		int ny=r.front().y;
		for(int i=0;i<=3;i++)
		{
			int tx=nx+dx[i];
			int ty=ny+dy[i];
			if(!(tx>=1&&tx<=n&&ty>=1&&ty<=m)) continue;
			if(a[tx][ty]==0||v[tx][ty]==1) continue;
			temp.x=tx;
			temp.y=ty;
			v[tx][ty]=1;
			r.push(temp);
		}
		r.pop();
	}
} 

大家继续努力!拜拜~

### 使用队列操作处理由数字0-9构成的矩阵中的细胞 在讨论如何通过队列来处理个由数字09组成矩形阵列时,可以考虑广度优先搜索(BFS算法。此方法特别适用于遍历或搜索图形结构,在这种情况下是指二维数组或者说是网格。 #### 初始化队列 创建队列用于存储待访问的位置坐标。通常这些位置是从某个起始点开始,比如含有特定值(即19之间的数)的个单元格作为起点加入队列中。 #### 队列入队与出队逻辑 对于每个从队列取出的元素,检查其相邻四个方向上的邻居节点(上、下、左、右),如果它们满足条件——在这个例子中就是等于指定范围内(1~9)未被访问过的数值,则将其标记为已访问并入队等待后续处理[^1]。 ```python from collections import deque def bfs(matrix, start_x, start_y): rows = len(matrix) cols = len(matrix[0]) directions = [(0, 1), (1, 0), (-1, 0), (0, -1)] # 右 下 上 左 queue = deque([(start_x, start_y)]) visited = set((start_x, start_y)) while queue: x, y = queue.popleft() for dx, dy in directions: nx, ny = x + dx, y + dy if 0 <= nx < rows and 0 <= ny < cols \ and matrix[nx][ny] != 0 and (nx, ny) not in visited: print(f&#39;Visiting cell ({nx}, {ny}) with value {matrix[nx][ny]}&#39;) visited.add((nx, ny)) queue.append((nx, ny)) # 假设有个5x5的矩阵 example_matrix = [ [0, 2, 3, 4, 5], [1, 6, 7, 8, 9], [0, 0, 0, 0, 0], [1, 2, 3, 4, 5], [6, 7, 8, 9, 0] ] bfs(example_matrix, 0, 1) ``` 上述代码展示了如何利用Python实现基本的广度优先搜索功能,其中`deque()`用来高效管理队列数据结构;同时注意边界情况以及避免重复访问相同位置。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值