题目如下:
一个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”方法。
当然,这道题目一定还有更加简单的实现方法,望大家学习与交流,本篇文章不足之处请多多包涵与指正。