题目描述
一矩形阵列由数字 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的时候说明那个方向为临界点,不再是这个细胞团的组成,此时就停止这个方向的搜索。这样搜索结束后,就可以完整的找出一个细胞团了。
后面的几行是同样的道理,就不赘述了。
这道题的讲解就到这里了,希望对你能有所帮助!