洛谷P1451 求细胞数量 用一道题理解DFS

题目描述

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

输入格式

第一行两个整数代表矩阵大小 n 和 m。

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

输出格式

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

输入输出样例

输入

4 10
0234500067
1034560500
2045600671
0000000089

输出 

4

这是一道普及-难度的DFS,非常的经典。

首先提供AC代码

#include<stdio.h>
int m,n,ans;
int cell[105][105],book[105][105];//cell数组代表细胞,book数组来判断该细胞是否被判断过
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};//代表了上下左右四个移动方式,也可以将dx,dy封装在一个结构体中
void dfs(int x,int y)
{
	book[x][y]=1;//表示这个数已经判断过
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i];
		int ny=y+dy[i];
		if(cell[nx][ny]==0||book[nx][ny]==1) continue;//如果新判断的细胞是0或已经被判断过,那么就判断另一个方向的细胞
		dfs(nx,ny);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) scanf("%1d",&cell[i][j]);//因为每个数字之间没有空格,故采用这种形式输入
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			if(book[i][j]==0&&cell[i][j]!=0)//如果次数没有被判断过,且此数不为0,则执行dfs
			{
				dfs(i,j);
				ans++;
			}
		}
	printf("%d\n",ans);
	return 0;
}

在我写代码的时候,还有一个疑惑:为什么每次dfs之前就会ans++,难道不会多计数吗?

其实,

if(book[i][j]==0&&cell[i][j]!=0)

这个语句就已经能防止重复计数了。并且,如果一个细胞不为0,那么如下两种情况

         0                                                                        0        1        1  

    0   1   0                                                                   1        1        0

         0                                                                        0        1        0

即单个细胞和细胞团。

用DFS可以非常有效的搜索第二种情况。 

看到这里,你是不是还是不太理解代码的意思?

没关系,加入几行测试代码,就会让整个代码清晰起来

第一个测试代码:

#include<stdio.h>
int m,n,ans;
int cell[105][105],book[105][105];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
void dfs(int x,int y)
{
	book[x][y]=1;//表示这个数已经判断过
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i];
		int ny=y+dy[i];
		if(cell[nx][ny]==0||book[nx][ny]==1) continue;
		dfs(nx,ny);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) scanf("%1d",&cell[i][j]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(book[i][j]==0&&cell[i][j]!=0)
			{
				dfs(i,j);
				ans++;
			}
		}
		printf("----------------\n");
				for(int k=1;k<=n;k++)
				{
					for(int u=1;u<=m;u++) {
					printf("%d",book[k][u]);
					
			     	}
				    printf("\n");
				}
				printf("\n");
	}
		
	printf("%d\n",ans);
	return 0;
}

第二个测试的代码:

#include<stdio.h>
int m,n,ans;
int cell[105][105],book[105][105];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
void dfs(int x,int y)
{
	book[x][y]=1;//表示这个数已经判断过
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i];
		int ny=y+dy[i];
		if(cell[nx][ny]==0||book[nx][ny]==1) continue;
		dfs(nx,ny);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) scanf("%1d",&cell[i][j]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(book[i][j]==0&&cell[i][j]!=0)
			{
                printf("(%d     %d):%d\n",i,j,cell[i][j]);
				dfs(i,j);
				ans++;
			}
		}
	}
		
	printf("%d\n",ans);
	return 0;
}

两个测试代码的运行结果结合起来看:

由运行结果我们可以看出DFS的具体执行过程

判断第一行时,如果一个细胞不为0,那么就以这个点为中心,同样的用dfs来判断他的上下左右是否为细胞,同样的,也会搜索上下左右细胞的上下左右细胞,当一个方向碰到0的时候说明那个方向为临界点,不再是这个细胞团的组成,此时就停止这个方向的搜索。这样搜索结束后,就可以完整的找出一个细胞团了。

后面的几行是同样的道理,就不赘述了。

这道题的讲解就到这里了,希望对你能有所帮助!

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值