图像物体的边界- 华为OD统一考试(C卷)

OD统一考试(C卷)

分值: 200分

题解: Java / Python / C++

alt

题目描述

给定一个二维数组M行N列,二维数组里的数字代表图片的像素,为了简化问题,仅包含像素1和5两种像素,每种像素代表一个物体2个物体相邻的格子为边界,求像素1代表的物体的边界个数。

像素1代表的物体的边界指与像素5相邻的像素1的格子,边界相邻的属于同一个边界,相邻需要考虑8个方向(上,下,左,右,左上,左下,右上,右下)。

其他约束:地图规格约束为:

  • 0<M<100
  • 0<N<100

image-20240303122632439

输入描述

第一行,行数M, 列数N

第二行开始,是M行N列的像素的二维数组,仅包含像素1和5

输出描述

像素1代表的物体的边界个数。如果没有边界输出0(比如只存在像素1,或者只存在像素5)。

示例1

输入:
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

示例2

输入:
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	5	1
1	1	1	1	1	1

输出:
1

题解

解题思路

这是一个图的深度优先搜索(DFS)问题。题目要求统计像素1代表的物体的边界个数,而像素1的边界是与像素5相邻的位置。因此,我们可以首先预先处理一下像素5的位置,将与之相邻的像素1标记为可能是边界的位置(用数字0表示)。然后,利用深度优先搜索(DFS)来统计与边界相连的区域的数量,每一轮搜索即为一组边界。

具体步骤如下:

  1. 读取输入,包括行数 rows、列数 cols 以及像素的二维数组 grid
  2. 遍历 grid,当遇到像素值为5时,预先标记其周围8个位置为0,表示可能是边界。这里可以使用两层嵌套循环遍历周围的位置,并将对应位置的像素值标记为0。
  3. 使用深度优先搜索(DFS)来统计与边界相连的区域数量。定义一个函数 dfs,在该函数中,首先检查当前坐标是否有效且对应位置的像素值为0。如果满足条件,则将当前位置的像素值标记为1,并递归地调用 dfs 函数,搜索其周围的8个位置。
  4. 主循环遍历整个二维数组 grid,对每个像素值为0的位置调用 dfs 函数,统计边界的数量。
  5. 输出最终结果。

Java

import java.util.Scanner;
/**
 * @author code5bug
 */
public class Main {
    // 行数,列数
    static int rows, cols;

    // 验证坐标有效性
    static boolean valid(int r, int c) {
        return 0 <= r && r < rows && 0 <= c && c < cols;
    }

    // 深度优先搜索,标记为 0 的位置就是边界,之后搜索其周围的 0 的位置,并标记为 1 。
    // 将所有相关联的都标记为 1
    static void dfs(int[][] grid, int r, int c) {
        if (!valid(r, c) || grid[r][c] != 0) return;
        grid[r][c] = 1;

        for (int dr = -1; dr < 2; dr++) {
            for (int dc = -1; dc < 2; dc++) {
                int nr = r + dr, nc = c + dc;
                dfs(grid, nr, nc);
            }
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        rows = scanner.nextInt();
        cols = scanner.nextInt();

        int[][] grid = new int[rows][cols];

        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                grid[r][c] = scanner.nextInt();
            }
        }

        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                if (grid[r][c] == 5) {  // 预打标  grid[r][c] = 0, 表示 (r, c) 为边界坐标
                    for (int dr = -1; dr < 2; dr++) {
                        for (int dc = -1; dc < 2; dc++) {
                            int nr = r + dr, nc = c + dc;
                            if (valid(nr, nc) && grid[nr][nc] == 1) {
                                grid[nr][nc] = 0;   // 标记为可能是边界
                            }
                        }
                    }
                }

            }
        }

        int result = 0;
        for (int r = 0; r < rows; r++) {
            for (int c = 0; c < cols; c++) {
                if (grid[r][c] == 0) {
                    // 每一轮搜索即为一组边界
                    dfs(grid, r, c);
                    result++;
                }
            }
        }

        System.out.println(result);
    }
}

Python

def valid(r, c):
    # 验证坐标的有效性
    return 0 <= r < rows and 0 <= c < cols


def dfs(grid, r, c):
    # 深度优先搜索,标记为 0 的位置表示边界,然后搜索其周围的 0 的位置,并标记为 1。将所有相关联的位置都标记为 1。
    if not valid(r, c) or grid[r][c] != 0:
        return
    grid[r][c] = 1

    for dr in range(-1, 2):
        for dc in range(-1, 2):
            nr, nc = r + dr, c + dc
            dfs(grid, nr, nc)


if __name__ == "__main__":
    # 读取输入
    rows, cols = map(int, input().split())
    grid = [list(map(int, input().split())) for _ in range(rows)]

    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == 5:
                # 预先标记 grid[r][c] = 0,表示 (r, c) 为边界坐标
                for dr in range(-1, 2):
                    for dc in range(-1, 2):
                        nr, nc = r + dr, c + dc
                        if valid(nr, nc) and grid[nr][nc] == 1:
                            grid[nr][nc] = 0  # 标记为可能是边界

    result = 0
    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == 0:
                # 使用深度优先搜索统计与边界相连的区域数量
                dfs(grid, r, c)
                result += 1

    # 输出结果
    print(result)

C++

#include <bits/stdc++.h>
using namespace std;

int rows, cols;

// 验证坐标有效性
bool valid(int r, int c)
{
    return 0 <= r && r < rows && 0 <= c && c < cols;
}

// 深度优先搜索,标记为 0 的位置就是边界,之后搜索其周围的 0 的位置,并标记为 1 。
// 将所有相关联的都标记为 1
void dfs(vector<vector<int>>& grid, int r, int c)
{
    if (!valid(r, c) || grid[r][c] != 0) return;
    grid[r][c] = 1;

    for (int dr = -1; dr < 2; dr++) {
        for (int dc = -1; dc < 2; dc++) {
            int nr = r + dr, nc = c + dc;
            dfs(grid, nr, nc);
        }
    }
}

int main()
{
    cin >> rows >> cols;
    vector<vector<int>> grid(rows, vector<int>(cols, 0));

    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
            cin >> grid[r][c];
        }
    }

    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
            if (grid[r][c] == 5) {   // 预打标  grid[r][c] = 0, 表示 (r, c) 为边界坐标
                for (int dr = -1; dr < 2; dr++) {
                    for (int dc = -1; dc < 2; dc++) {
                        int nr = r + dr, nc = c + dc;
                        if (valid(nr, nc) && grid[nr][nc] == 1) {
                            grid[nr][nc] = 0;   // 标记为可能是边界
                        }
                    }
                }
            }
        }
    }

    int result = 0;
    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
            if (grid[r][c] == 0) {
                dfs(grid, r, c);
                result++;
            }
        }
    }

    cout << result << endl;
}    

‍❤️‍华为OD机试面试交流群每日真题分享): 加V时备注“华为od加群”

🙏整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/424729.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言中的字符魔法:大小写转换的艺术

引言 在C语言的世界里&#xff0c;字符处理是一项基础且重要的任务。字符作为编程中最基本的元素之一&#xff0c;承担着信息展示、数据交互等多重角色。特别是在处理文本信息时&#xff0c;字符的转换和识别显得尤为重要。大小写字母的转换就是其中一个常见的需求&#xff0c…

STM32作为SPI slave与主机异步通信

背景 最近被测试提了个BUG&#xff0c;说某款产品在用户按下前面板的按键后&#xff0c;对应的按键灯没有亮起来。前面板跟主机是通过SPI口通信&#xff0c;前面板是从机&#xff0c;从机想要主动发送消息&#xff0c;需要通过GPIO中断来通知主机&#xff1a; 上图前面板是ST…

flurl升级之后没有FlurlNewtonsoftJsonSerializer

新建NewtonsoftJsonSerializer.cs /// <summary> /// ISerializer implementation based on Newtonsoft.Json. /// Default serializer used in calls to GetJsonAsync, PostJsonAsync, etc. /// </summary> public class NewtonsoftJsonSerializer : IJsonSerial…

【CSP试题回顾】202312-1-仓库规划

CSP-202312-1-仓库规划 解题思路 定义结构体和变量&#xff1a; 结构体 MyWareHouse&#xff0c;用来存储每个仓库的索引&#xff08;编号&#xff09;和位置编码。定义了整数 n 和 m&#xff0c;分别代表仓库的数量和位置编码的维数。定义了一个 vector<MyWareHouse> 的…

图解Vivado工程的目录结构

一、目录结构 ​在使用Vivado进行工程设计时&#xff0c;创建工程以及运行工程的过程中都会生成大量的目录和文件&#xff0c;下面图将对目录和文件结构及功能进行一个简单说明。 工程示例图 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 二、参考资料…

ShardingJdbc分库分表-浅谈分表原理

文章目录 为什么要分库分表一、分库分表二、不停机分库分表数据迁移 为什么要分库分表 一般的机器&#xff08;4核16G&#xff09;&#xff0c;单库的MySQL并发&#xff08;QPSTPS&#xff09;超过了2k&#xff0c;系统基本就完蛋了。最好是并发量控制在1k左右。这里就引出一个…

kubesphere jenkins 流水线 未运行(解决方案)

场景&#xff1a; 在kubesphere 中运行 流水线 devops 结果&#xff0c;显示未运行 但是用 admin 账户是可以运行成功的。 问题解决 1- 查日志&#xff1a; 然后 Caused: org.acegisecurity.userdetails.UsernameNotFoundException: org.springframework.security.core.…

JVM运行时数据区——运行时数据区及线程概述

文章目录 1、运行时数据区概述2、线程3、小结 内存是非常重要的系统资源&#xff0c;是硬盘和CPU的中间仓库及桥梁&#xff0c;承载着操作系统和应用程序的实时运行。JVM在程序执行期间把它所管理的内存分为若干个不同的数据区域。这些不同的数据区域可以分为两种类型&#xff…

吴恩达机器学习全课程笔记第六篇

目录 前言 P96-P100 使用多个决策树 随机森林算法 XGBoost 什么时候使用决策树 P101-P107 聚类 K-means 初始化K-means 选择聚类的个数 P108-P113 异常检测算法 开发和评估异常检测系统 异常检测vs监督学习 选择要使用的特征 前言 这是吴恩达机器学习笔记的第…

【嵌入式实践】【芝麻】【设计篇-2】从0到1给电动车添加指纹锁:项目可行性分析

0. 前言 该项目是基于stm32F103和指纹模块做了一个通过指纹锁控制电动车的小工具。支持添加指纹、删除指纹&#xff0c;电动车进入P档等待时计时&#xff0c;计时超过5min则自动锁车&#xff0c;计时过程中按刹车可中断P档状态&#xff0c;同时中断锁车计时。改项目我称之为“芝…

基于反光柱特征的激光定位算法思路

目录 1. 识别反光柱2. 数据关联2.1 基于几何形状寻找匹配2.2 暴力寻找匹配 3. 位姿估计&#xff08;最小二乘求解&#xff09;4. 问题4.1 精度问题4.2 快速旋转时定位较差 1. 识别反光柱 反光柱是特殊材料制成&#xff0c;根据激光雷达对反光材料扫描得到的反射值来提取特征。…

如何解决微服务的数据一致性分发问题?

介绍 系统架构微服务化以后,根据微服务独立数据源的思想,每个微服务一般具有各自独立的数据源,但是不同微服务之间难免需要通过数据分发来共享一些数据,这个就是微服务的数据分发问题。Netflix/Airbnb等一线互联网公司的实践[参考附录1/2/3]表明,数据一致性分发能力,是构…

京东云硬钢阿里云:承诺再低10%

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 阿里云刚刚宣布史上最大规模的全线产品降价20%&#xff0c;这热度还没过&#xff0c;京东云当晚就喊话&#xff1a;“随便降、比到底!&#xff0c;全网比价&#xff0c;击穿低价&#xff0c;再低10%”&#xff0c;并…

求最短路径之BF算法

介绍 全称Bellman-Ford算法&#xff0c;目的是求解有负权边的最短路径问题。 考虑环&#xff0c;根据环中边的边权之和的正负&#xff0c;将环分为零环、正环、负环。其中零环、正环不会影响最短路径的求解&#xff0c;而负环会影响最短路径的求解。 可用BF算法返回一个bool值…

Redis之十:Spring Data Redis --- CrudRepository方式

SpringData Redis CrudRepository方式 Spring Data Redis 的 CrudRepository 是 Spring Data 框架中用于提供基础 CRUD&#xff08;创建、读取、更新和删除&#xff09;操作的一个接口。在与 Redis 集成时&#xff0c;尽管 Redis 是一个键值存储系统&#xff0c;并没有像关系型…

【达梦数据库】如何使用idea antrl4插件方式dm sql

使用idea中的antrl插件进行分析 1.打开IDEA&#xff0c;在File—Settings—Plugins中&#xff0c;安装ANTLR v4 grammar plugin插件。 2.加载达梦的语法文件 3.配置生成路径和目录&#xff08;可采用默认&#xff09; 4.编译DmSqlParser.g4 DmSqlLexer.g4 5.输入SQL/输入文件 …

用Flutter开发App:助力您的移动业务腾飞

一、Flutter简介 Flutter是Google推出的用于构建多平台应用程序的开源UI框架。它使用Dart语言编写&#xff0c;可以编译为原生机器代码&#xff0c;从而提供卓越的性能和流畅的用户体验。 二、Flutter的优势 一套代码&#xff0c;多平台部署&#xff1a;Flutter可以使用一套代…

electron安装最后一部卡住了?

控制台如下错误 不是的话基本可以划走了 这个很可能是镜像出现问题了&#xff0c;不一定是npm镜像 打开npm的配置文件添加下述 electron_mirrorhttps://cdn.npmmirror.com/binaries/electron/ electron_builder_binaries_mirrorhttps://npmmirror.com/mirrors/electron-build…

将本地的镜像上传到私有仓库

使用register镜像创建私有仓库 [rootopenEuler-node1 ~]# docker run --restartalways -d -p 5000:5000 -v /opt/data/regostry:/var/lib/registry registry:2[rootopenEuler-node1 ~]# docker images REPOSITORY TAG IMAGE…

JAVAEE初阶 JVM(二)

垃圾回收和双亲委派模型 1.双亲委派模型2.垃圾回收机制(1) 识别垃圾1.引用计数2.可达性分析 (2) 销毁垃圾1.标记清除2.复制算法3.标记整理 3.分代回收 1.双亲委派模型 描述了如何查找.class文件的策略. 同时JVM中有专门进行类加载的操作,有一个模块,叫做类加载器. 上述就是为了…