【二维数组】相邻区域/相邻区块数(数组元素的类平面坐标表示方法以及遍历)

题目如下:

一个n行m列的矩阵被划分成t个矩形区域,分别用数字1-t来标识,同一个区域内的元素都用同一个数字标识。如下图所示,一个6行8列的矩阵被分成8个矩形区域,分别用编号1-8标识。当两个小区域之间公用一条边时,称这两个区域相邻,例如下图中区域5的相邻区域有6个,分别为1,2,3,6,7,8,但4并不是它的相邻区域。请写一个程序找出区域k的所有相邻区域。
在这里插入图片描述
输入说明

输入第一行为四个整数n,m, t,k,整数之间用空格分隔。n表示矩阵行数(n<20),m表示矩阵列数(m<20),t表示矩阵被划分为t个矩形区域(0<t<50),k为其中某个区域的编号(1<=k<=t)。接下来是n行数据,每行m个整数,表示矩阵内各个元素所在的区域,整数之间用空格分隔。

输出说明

输出为一个整数,表示与k相邻的区域个数

输入样例

6 8 8 5
1 1 2 2 2 3 3 4
1 1 2 2 2 3 3 4
1 1 2 2 2 3 3 4
1 1 5 5 5 5 5 6
1 1 5 5 5 5 5 6
7 7 7 7 7 8 8 8

输出样例

6

.
.
.
此问题看似复杂,其实分解成几个小问题去逐一解决,代码很容易就可以写出。我们用二维数组处理数据,遇到如下几个问题:
【我们首先将整个数字网络置于一个类平面直角坐标系中,双重循环变量i和j分别控制列(y轴)和行(x轴)的变化,具体的图解如下】:
在这里插入图片描述

①如何定位数字为k的矩形?
→我们知道,矩形有四条边。而一个矩形的大小和位置可以仅由“左上角”和“右下角”两个点的位置来确定(就像我们在电脑中拉出矩形框一样)。所以,我们需要获得数字为k的矩形的位置,只需要获得这两个点的坐标(xmin,ymin)和(xmax,ymax)。见上图。

②如何统计相邻的区块数?
→如此的单纯的数字统计,我倾向于之前介绍过的“计数器judge”方法。【详见博客https://blog.csdn.net/GalaxyerKw/article/details/110310346
对该矩形周围一圈(正上,正下,正左,正右)的数字进行遍历判断。

③如何保证遍历判断时,数组不越界?
→在对应的for循环内增加if条件限制即可。
.
.
.
解决了上述问题,我们就可以写代码了:

#include<stdio.h>

int main(void)
{
  int n,m,t,k;  //n表示矩阵行数(n<20),m表示矩阵列数(m<20),t表示矩阵被划分为t个矩形区域(0<t<50),k为其中某个区域的编号(1<=k<=t)。
  scanf("%d%d%d%d",&n,&m,&t,&k);
  int p[n][m];
  int i,j;
 for (i=0; i<=n-1; i++)
 {
   for (j=0; j<=m-1; j++)
   {
     scanf("%d",&p[i][j]);
   }
 }
   //思路是先找出数字为k的矩形所在位置,再在其周围一圈遍历,看有几个不同的数
  int xmin,ymin,xmax,ymax;
  int flag=1;
 for (i=0; i<=n-1; i++)    //最左上坐标(xmin,ymin)
 {
   for (j=0; j<=m-1; j++)
   {
     if (p[i][j]==k)
     {
       xmin=j;
       ymin=i;
       flag=0;
     }
     if (flag==0)  break;
   }
    if (flag==0)  break;
 }

 for (i=n-1; i>=0; i--)   //最右下坐标(xmax,ymax)
 {
   for (j=m-1; j>=0; j--)
   {
     if (p[i][j]==k)
     {
       xmax=j;
       ymax=i;
       flag=1;
     }
     if (flag==1)  break;
   }
    if (flag==1)  break;
 }

   //调试位置坐标是否正确,可用下方注释中的程序:
   //printf("\n%d %d %d %d\n",xmin,ymin,xmax,ymax);

  int judge[t+1];  //开辟计数器0-t并归零
 for (i=0; i<=t; i++) {judge[i]=0;}

  for (j=xmin; j<=xmax; j++)  //同时检验上边和下边一行
  {
      if (j>=0 && j<=m-1 && ymin-1>=0)   //上方不能越界
      {
          judge[p[ymin-1][j]]++;
      }
      if (j>=0 && j<=m-1 && ymax+1<=n-1)  //下方不能越界
      {
          judge[p[ymax+1][j]]++;
      }
  }
  for (i=ymin; i<=ymax; i++) //再同时检验左边和右边一行
  {
      if (i>=0 && i<=n-1 && xmin-1>=0)  //左方不能越界
      {
          judge[p[i][xmin-1]]++;
      }
      if (i>=0 && i<=n-1 && xmax+1<=m-1) //右方不能越界
      {
          judge[p[i][xmax+1]]++;
      }
  }
    //此时计数器已经储存完毕所有出现过的数字,现在开始遍历计数器
  int sum=0;
  for (i=0; i<=t; i++)
  {
      if (judge[i]!=0)  sum++;
  }
  printf("%d",sum);

 return 0;
}

此题并不难,但是其思想值得我们学习。
其思想的精华在于,将一个二维数字数组置于一个类平面直角坐标系中,通过坐标进行判断与计算,同时使用了便于统计的“计数器judge”方法。

当然,这道题目一定还有更加简单的实现方法,望大家学习与交流,本篇文章不足之处请多多包涵与指正。

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值