21天学习挑战赛--图像物体的边界

活动地址:CSDN21天学习挑战赛

题目描述

给一个二维数组M行N列,数组中的数字代表图片的像素,为了简化问题,仅包含像素1和5两种像素,每种像素代表一个物体,将两个不同物体相邻的格子称为边界,求像素1代表的边界个数。(0<M<100,0<<100)

其中像素1代表的物体边界是指像素为1并且与像素5相邻的格子,而相邻的概念是指八个方向(上、下、左、右、左上、左下、右上、右下)的相近。

如上图,其中黄色部分即为边界,根据相邻的概念,黄色的格子组成了两个边界。

上图中的黄色格子据相邻的概念只有一个边界。

输入示例

6 6

1 1 1 1 1 1

1 5 1 1 1 1

1 1 1 1 1 1

1 1 1 1 1 1

1 1 1 1 1 1

1 1 1 1 1 5

输出

2

解析见上图

思考

解决这个问题可以分为两步:

  • 确定边界格子

  • 判断边界格子所属边界的个数

那么就有了解决问题的思路,第一步确定边界格子,可以将5周围的格子标记出来,这里是数组,那就赋一个不是1、5的值就好了,这里用2标记,于是我们有了:

2 2 2 1 1 1

2 5 2 1 1 1

2 2 2 1 1 1

1 1 1 1 1 1

1 1 1 1 2 2

1 1 1 1 2 5

这样所有的边界格子被标记出来了,然后第二步判断边界格子所属边界,那么就是找2的格子,找到一个2的格子a便立即根据相邻规律将所有与格子a相邻的所有为2的格子变为3,那么找到2的次数便是边界的个数。

3 3 3 1 1 1

3 5 3 1 1 1

3 3 3 1 1 1

1 1 1 1 1 1

1 1 1 1 3 3

1 1 1 1 3 5

代码

根据上面的思考,里面都有一个给相邻格子赋值的操作,先抽象成方法。

	/**给相邻的格子赋值,pixel为当前值,target为目标值,只有当前值为pixel才会有赋值操作
	  *i,j分别对应数组中中心点的位置
	  *recursion确定是否为递归
	  */
public void put(int i, int j, int[][] array, int pixel, int target, boolean recursion) {
    //遍历上、中、下
    for (int a=-1;a<=1;a++){
        //遍历左、中、右
        for (int b=-1;b<=1;b++) {
            //确保数组下标不越界,并且数组当前位置的值为指定像素值pixel
            if (i+a < array.length && i+a >= 0 &&
            j+b < array[0].length && j+b >= 0 &&
            array[i+a][j+b] == pixel) {
                array[i+a][j+b] = target;
                //递归
                if (recursion) {
                    put(i+a,j+b, array, pixel, target, true);
                }
            }
        }
    }
}

此处定义的方法 put() 主要功能是将数组当前位置的所有相邻部分并且其像素pixel为指定值的格子赋上目标值target,当递归recursion为true时,会将根据相邻规则画出的一个块都赋上目标值。

第二步,判断边界个数,用上面的方法递归计算边界的个数。

public static void main(String[] args) {
    //初始化数组
    int[][] a = new int[6][6];
    for (int i=0;i<a.length;i++) {
        for (int j=0;j<a[0].length;j++){
            a[i][j] = 1;
        }
    }
    a[1][1] = 5;
    a[5][5] = 5;
    
    //标记像素5的边界,用2标记
    for (int i=0;i<a.length;i++) {
        for (int j=0;j<a[0].length;j++){
            if (a[i][j] == 5)
                //调用put方法标记边界
                put(i,j,a,1,2,false);
        }
    }
    
    //统计边界个数
    int count = 0;
    for (int i=0;i<a.length;i++) {
        for (int j=0;j<a[0].length;j++){
            //找到2的格子,并递归标记
            if (a[i][j] == 2) {
                put(i, j, a, 2, 3, true);
                count ++;
            }
        }
    }
    System.out.println("边界个数:" + count);
}

其实这里还可以尝试用不同的值标记不同的边界,那么也许更明显,但是在尝试过程中,一定要避免2、1之类的已经出现的值,可能让递归陷入死循环,会报栈溢出错误。
至此,问题解决。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值