求水洼数目

题目描述:

小曾家有一片方地,下雨之后,地里面有水洼也有平地,总体显得凹凸不平,每个小水洼周围如果也有水洼的话,两个小水洼就一起合成一个大水洼;大水洼周围如果有水洼就会又转换成一个更大的水洼;以此类推,小曾想求出水洼的数目,将现实问题转换成C语言问题:

    输入一个二维数组,用0表示没有水坑,用1表示有水坑,方便理解,生活中,小水洼周围(360°)遇到另一个水洼都会与另一个水洼合成一个水洼,在这里我们简化问题,设水洼的上下左右四个方位遇到另一个水洼会与另一个水洼合成一个水洼。我们把假设这是一个一块四行四列的二维数组(更多行更多列也是此原理,以此类推),我随机输入这样一组数字:

   1    1   0   0                                                                                                                                         1    0   1   1                                                                                                                                         0    1   0   0                                                                                                                                         0    1   0   1

整体思路:

我们自己先数一数,一共有多少个水洼?显而易见,一共有四个,如下图所示:

(有点丑)

这是我们能数到的,但是计算机怎么能计算出来呢?比如我们先以第一行第一列的元素来看,a[0][0]是1,这里有水坑,我们要观察它的上下左右四个方位,下面我们也以这个顺序来观察;a[0]0]的上方没有元素,下方a[1][0]是1,左方没有元素,右方是a[0][1]也为1,同样,我们还要判断a[0][0]的上下左右为1的元素周围有没有1,如果有的话,需要把它们一起并为一个水洼。

接着判断,a[1][0]上方是1,但是它本身就是从a[0][0]判断下来的,要怎样才能摒除掉这一个元素呢?那我们就让系统先自动帮我们填一下水坑。

也就是说,刚刚a[0][0]有水坑为1,当我们判断它的上下左右时,我们先让它变为0,这样一来,无论是它下方有水坑,还是它右边有水坑,我们都可以用一套判断方法去进行(即判断上下左右);

好,现在我们已经有了系统帮我们自动填水坑的设定(我们设定的);

这里需要说明:每个元素都是按照上下左右的顺序去判断它的周围有没有水坑,每个元素先判断自己是不是水坑,我们假设为a,如果是,a=1,就先判断它的上方,如果上方也是水坑,那么,a=0(只要a自己本身是水坑,去判断上下左右的时候先把自己填平),这里需要用到一个计算水坑数目的元素,假设为water_sum;假设为b,就以上方水坑为一个中心点,开始我们的上下左右判断法则去判断(这里先不判断最开始的那个元素的下方左右方);现在b的下方a变为0,如果现在判断b的上方和左右方,如果都没有,都为0,我们就结束本次判断,开始下一个元素判断;

以上是判断法则;

按照我们举的例子,这个时候系统先去判断a[0][0],发现它是1,首先将它置为0,再去判断它的上方(没有元素),判断它的下方(a[1][0]为1:将它置0(去判断它的上方:a[0][0]=0,下方:a[2][0]为0,左边:没有元素,右边:为0,现在可以跳出这个判断)),判断它(a[0][0])的左边:没有元素,判断它的右边:a[0][1]为1(现将他置0,判断它(a[0][1]的上方:没有元素,下方:a[1][1]=0;左边:a[0][0]=0(已经被变为0),右边:a[0][2]=0,现在跳出这个判断),至此,第一个元素完全判断完毕,这个时候,水洼数目water_sum=1(由此可知在程序中水洼的初始值应为0);现在开始判断第二个元素:a[0][1],通过第一个元素的判断,a[0][0]=0,a[0][1]=0,a[1][0]=0,,所以第二个元素为0,不进行判断,水洼数目仍为1;第三个元素判断:a[0][2]=0,不进行判断,水洼数目仍为1;一直进行,直到第二行第三个元素,a[1][2]=1,首先先将它置为0,再判断它的上方a[0][2]=0,下方:a[2][2]=0,左边:a[1][1]=0,右边:a[1][3]=1(首先将它置为0,再去判断它的上下左右,发现都为0,它的左边元素a[1][2]已经被置为0,现在跳出这个判断),至此a[1][2]的判断也结束,这时,水坑数目加1,现在的水坑数目为2;依次类推,对接下来的每个元素都进行判断。


这里有个很巧妙的点:每次判断完这个数值后将它置为0,这样下面的元素就可以按照同样的方法去判断,在后面的判断中就不会被重复去判断了(就比如,a[0][0]=1,如果它不被置为1,再第二个元素a[0][1]判断时就是被重复判断),所以说这个点很巧妙!


 程序实现时,我们用两个函数去解决这个问题:一个函数进行上下左右的判断(遍历法则:递归函数),另一个函数,进行水坑数目的计算。先去判断这块地(这个数值)是不是水坑,然后再去上下左右判断有没有别的水坑(在判断出来的水坑周围再去判断有没有别的水坑),递归去判断,这个时候整体结束后,水坑数目加1;

函数实现:

第一个函数:
 /*   函数名:water  
      函数变量:@a:二维数组
                        @m:二维数组的行数
                        @I,j:遍历数组的

        返回值:没有,只需要进行连续的判断并将原来是1的元素置0就可以了     */

这里注意,判断的范围,因为每个数组它是有界限的,我们要在界限范围内去判断,否则出来的结果会有点不准确,判断的方法和规则可以描述如下,:

void water(int a[][6],int m,int i,int j)
{
    if(a[i][j]==1)//如果有水洼的情况 
    {
        a[i][j]=0;    //重点:就把水洼填平 
        if(i-1<4)                                      //行范围:[0-3]
        {
            water(a,4,i-1,j);//上面的行
        }
        if(i+1>0)
        {
            water(a,4,i+1,j)//下面的行 
        }
        if(j-1<4)
        {
            water(a,4,i,j-1);//左边的列
         } 
        if(j+1>0)
        {
            water(a,4,i,j+1);//右边的列
        }
    }
}

第二部分:
  /*       函数名:water_sum,求水洼数量的
            函数变量:@m:行数
                              @a:二维数组名
            返回值:      int 水坑的数量                            */

自动加水坑数目的部分代码:

int water_sum(int a[][4],int m)
{
    int i,j;
    int sum=0;
    for(i=0;i<m;i++)
    {
        for(j=0;j<4;j++)
        {
            if(a[i][j]==1)
            {
                water(a,4,i,j);//整体判断完毕 
                sum++;//水坑数目加1 
            }
        }
    }

    return sum;
}

两个函数之间的联系

这里注意第一个函数和第二个函数之间的关系,函数的嵌套,第二个水坑数目判断里面,如果判断的正好是个水坑,数值正好是个1的话,需要对这个元素进行一次判断规则(第一个函数去递归一下),再使水坑数目加1; 

整体代码记录:

#include<stdio.h>
int water_sum(int a[][4],int m);//函数声明
//因为第一个函数只有在第二个函数中被用到,在主函数中没有明显的出现,所以不用声明
void water(int a[][4],int m,int i,int j)
{
	if(a[i][j]==1)//如果有水洼的情况 
	{
		a[i][j]=0;//就把水洼填平 
		if(i-1<4) 
		{
			water(a,4,i-1,j);//下面的行
		}
		if(i+1>0)
		{
			water(a,4,i+1,j);//上面的行 
		}
		if(j-1<m)
		{
			water(a,4,i,j-1);//左边的列 
		 } 
		if(j+1>0)
		{
			water(a,4,i,j+1);//右边的列 
		}
	}
}

int water_sum(int a[][4],int m)
{
	int i,j;
	int sum=0;
	for(i=0;i<m;i++)
	{
		for(j=0;j<4;j++)
		{
			if(a[i][j]==1)
			{
				water(a,4,i,j);//整体判断完毕 
				sum++;//水坑数目加1 
			}
		}
	}
	return sum;
}
int main()
{
	printf("本代码将实现二维数组中的水坑个数!\n");
	int num;
	printf("这里列数已经规定为4行,请输入你的菜地有几行?\n");
	scanf("%d",&num);
	printf("请输入你的菜地结构!\n");
	int a[num][4];
    int i,j;
    for(i = 0;i < num;i++)
    {
        for(j = 0;j < 4;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    printf("你的菜地有%d个水洼!\n",water_sum(a,4));
	return 0;
}

代码运行结果: 


 这是我在学C语言中,通过老师讲解和询问同学对自己的学习的一个总结,文中有不对或说法不准确的地方,恳请各位大佬指正!


本人的评论区欢迎大家讨论技术性的问题!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值