2023华为OD机试 (B卷)|200分图像物体的边界

2023华为OD机试 (B卷)|200分图像物体的边界(Java JavaScript C++ Python)
题目描述
给定一个二维数组M行N列,二维数组里的数字代表图片的像素,为了简化问题,仅包含像素1和5两种像素,每种像素代表一个物体,2个物体相邻的格子为边界,求像素1代表的物体的边界个数。
像素1代表的物体的边界指与像素5相邻的像素1的格子,边界相邻的属于同一个边界,相邻需要考虑8个方向(上,下,左,右,左上,左下,右上,右下)。
其他约束
地图规格约束为:

0 < M < 100
0 < N < 100

① 如下图与像素5的格子相邻的像素1的格子(0,0)(0,1)(0,2)(1,0)(1,2)(2,0)(2,2)(4,4)(4,5)(5,4)为边界,另(0,0)(0,1)(0,2)(1,0)(1,2)(2,0)(2,1)(2,2)相邻,为1个边界,(4,4)(4,5)(5,4)相邻,为1个边界,所以下图边界个数为2

111111
151111
111111
111111
511111
511111
② 如下图,与像素5的格子相邻的像素1的格子`(0,0)(0,1)(0,2)(1,0)(1,2)(2,0)(2,1)(2,2)(3,3)(3,4)(3,5)(4,3)(4,5)(5,3)(5,4)(5,5)`为边界,另这些边界相邻,所以下图边界个数为1。
111111
151111
111111
111111
111151
111111

注:(2,2)(3,3)相邻

输入描述

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

输出描述

像素1代表的物体的边界个数。
如果没有边界输出0(比如只存在像素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 1
输出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
输出2
说明参考题目描述部分

Java

import java.util.*;

class Main {
    static class UnionFindSet {
        int[] fa;
        int count;

        public UnionFindSet(int n) {
            fa = new int[n];
            for (int i = 0; i < n; i++) {
                fa[i] = i;
            }
            count = n;
        }

        public int find(int x) {
            if (x != fa[x]) {
                fa[x] = find(fa[x]);
            }
            return fa[x];
        }

        public void union(int x, int y) {
            int x_fa = find(x);
            int y_fa = find(y);
            if (x_fa != y_fa) {
                fa[y_fa] = x_fa;
                count--;
            }
        }
    }

    public static int getBoundaryCount(int[][] matrix, int m, int n) {
        List<int[]> brands = new ArrayList<>(); // 存储像素为5的格子的坐标

        // 找到所有像素为5的格子
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == 5) {
                    brands.add(new int[]{i, j}); // 将像素为5的格子的坐标存入brands中
                }
            }
        }

        int len = brands.size(); // 像素为5的格子的个数
        if (len == 0 || len == n * m) { // 特判:如果没有像素为5的格子或者所有格子都是像素为5的格子,则返回0
            return 0;
        }

        UnionFindSet ufs = new UnionFindSet(len); // 初始化并查集,节点个数为像素为5的格子的个数

        // 对于所有像素为5的格子,如果两个格子之间距离不超过3,则将它们合并到同一个连通块中
        for (int i = 0; i < len; i++) {
            for (int j = i + 1; j < len; j++) {
                int x1 = brands.get(i)[0], y1 = brands.get(i)[1];
                int x2 = brands.get(j)[0], y2 = brands.get(j)[1];

                if (Math.abs(x2 - x1) <= 3 && Math.abs(y2 - y1) <= 3) { // 如果两个格子之间距离不超过3
                    ufs.union(i, j); // 将它们合并到同一个连通块中
                }
            }
        }

        // 统计连通块的个数,即为像素1代表的物体的边界个数
        return ufs.count;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();
        int[][] matrix = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                matrix[i][j] = sc.nextInt();
            }
        }
        System.out.println(getBoundaryCount(matrix, m, n));
    }
}

Javascript

const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

class UnionFindSet {
  constructor(n) {
    this.fa = new Array(n).fill(0).map((_, i) => i); // 初始化每个节点的父节点为自己
    this.count = n; // 初始时有n个连通块
  }

  Find(x) { // 查找x所在的连通块的根节点
    if (x !== this.fa[x]) { // 如果x不是根节点
      this.fa[x] = this.Find(this.fa[x]); // 递归查找x的根节点,并将x的父节点设置为根节点,路径压缩优化
    }
    return this.fa[x]; // 返回x所在的连通块的根节点
  }

  Union(x, y) { // 将x和y所在的连通块合并
    const x_fa = this.Find(x); // 找到x所在的连通块的根节点
    const y_fa = this.Find(y); // 找到y所在的连通块的根节点
    if (x_fa !== y_fa) { // 如果x和y不在同一个连通块中
      this.fa[y_fa] = x_fa; // 将y所在的连通块的根节点的父节点设置为x所在的连通块的根节点
      this.count--; // 连通块的个数减1
    }
  }
}

function getBoundaryCount(matrix, m, n) {
  const brands = []; // 存储像素为5的格子的坐标

  // 找到所有像素为5的格子
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (matrix[i][j] === 5) {
        brands.push([i, j]); // 将像素为5的格子的坐标存入brands中
      }
    }
  }

  const len = brands.length; // 像素为5的格子的个数
  if (len === 0 || len === n * m) { // 特判:如果没有像素为5的格子或者所有格子都是像素为5的格子,则返回0
    return 0;
  }

  const ufs = new UnionFindSet(len); // 初始化并查集,节点个数为像素为5的格子的个数

  // 对于所有像素为5的格子,如果两个格子之间距离不超过3,则将它们合并到同一个连通块中
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      const [x1, y1] = brands[i];
      const [x2, y2] = brands[j];

      if (Math.abs(x2 - x1) <= 3 && Math.abs(y2 - y1) <= 3) { // 如果两个格子之间距离不超过3
        ufs.Union(i, j); // 将它们合并到同一个连通块中
      }
    }
  }

  // 统计连通块的个数,即为像素1代表的物体的边界个数
  return ufs.count;
}

let m, n;
const matrix = [];

rl.on('line', (line) => {
  if (!m) {
    [m, n] = line.split(' ').map(Number);
  } else {
    const row = line.split(' ').map(Number);
    matrix.push(row);
    if (matrix.length === m) {
      console.log(getBoundaryCount(matrix, m, n));
      rl.close();
    }
  }
});

C++

#include <iostream>
#include <vector>
using namespace std;

class UnionFindSet {
public:
  vector<int> fa; // 存储每个节点的父节点,初始化时每个节点的父节点为自己
  int count; // 连通块的个数
 
  UnionFindSet(int n) { // 初始化并查集,n为节点个数
    fa.resize(n); // 初始化fa数组的大小
    for (int i = 0; i < n; i++) {
      fa[i] = i; // 初始化每个节点的父节点为自己
    }
    count = n; // 初始时有n个连通块
  }
 
  int Find(int x) { // 查找x所在的连通块的根节点
    if (x != fa[x]) { // 如果x不是根节点
      fa[x] = Find(fa[x]); // 递归查找x的根节点,并将x的父节点设置为根节点,路径压缩优化
    }
    return fa[x]; // 返回x所在的连通块的根节点
  }
 
  void Union(int x, int y) { // 将x和y所在的连通块合并
    int x_fa = Find(x); // 找到x所在的连通块的根节点
    int y_fa = Find(y); // 找到y所在的连通块的根节点
    if (x_fa != y_fa) { // 如果x和y不在同一个连通块中
      fa[y_fa] = x_fa; // 将y所在的连通块的根节点的父节点设置为x所在的连通块的根节点
      count--; // 连通块的个数减1
    }
  }
};

int getBoundaryCount(vector<vector<int>>& matrix, int m, int n) {
  vector<pair<int, int>> brands; // 存储像素为5的格子的坐标

  // 找到所有像素为5的格子
  for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
      if (matrix[i][j] == 5) {
        brands.push_back(make_pair(i, j)); // 将像素为5的格子的坐标存入brands中
      }
    }
  }

  int len = brands.size(); // 像素为5的格子的个数
  if (len == 0 || len == n * m) { // 特判:如果没有像素为5的格子或者所有格子都是像素为5的格子,则返回0
    return 0;
  }

  UnionFindSet ufs(len); // 初始化并查集,节点个数为像素为5的格子的个数

  // 对于所有像素为5的格子,如果两个格子之间距离不超过3,则将它们合并到同一个连通块中
  for (int i = 0; i < len; i++) {
    for (int j = i + 1; j < len; j++) {
      int x1 = brands[i].first, y1 = brands[i].second;
      int x2 = brands[j].first, y2 = brands[j].second;

      if (abs(x2 - x1) <= 3 && abs(y2 - y1) <= 3) { // 如果两个格子之间距离不超过3
        ufs.Union(i, j); // 将它们合并到同一个连通块中
      }
    }
  }

  // 统计连通块的个数,即为像素1代表的物体的边界个数
  return ufs.count;
}

int main() {
  vector<vector<int>> matrix;
  int m, n;
  string line;

  // 读入输入数据
  getline(cin, line);
  sscanf(line.c_str(), "%d %d", &m, &n);

  for (int i = 0; i < m; i++) {
    getline(cin, line);
    vector<int> row;
    for (int j = 0; j < n; j++) {
      int num;
      sscanf(line.c_str() + j * 2, "%d", &num); // 读入每个格子的像素值
      row.push_back(num);
    }
    matrix.push_back(row); // 将每一行的像素值存入matrix中
  }

  // 输出结果
  cout << getBoundaryCount(matrix, m, n) << endl;

  return 0;
}

python

import sys
class UnionFindSet:
    def __init__(self, n):
        self.fa = list(range(n))
        self.count = n

    def find(self, x):
        if x != self.fa[x]:
            self.fa[x] = self.find(self.fa[x])
        return self.fa[x]

    def union(self, x, y):
        x_fa = self.find(x)
        y_fa = self.find(y)
        if x_fa != y_fa:
            self.fa[y_fa] = x_fa
            self.count -= 1
def getBrandCount(matrix, m, n):
    brands = []

    for i in range(m):
        for j in range(n):
            if matrix[i][j] == 5:
                brands.append([i, j])

    len_brands = len(brands)
    if len_brands == 0 or len_brands == n * m:
        return 0

    ufs = UnionFindSet(len_brands)

    for i in range(len_brands):
        for j in range(i + 1, len_brands):
            x1, y1 = brands[i]
            x2, y2 = brands[j]

            if abs(x2 - x1) <= 3 and abs(y2 - y1) <= 3:
                ufs.union(i, j)

    return ufs.count


lines = []
m = 0
n = 0
for line in sys.stdin:
    lines.append(line.strip())

    if len(lines) == 1:
        m, n = map(int, lines[0].split())

    if m and len(lines) == m + 1:
        lines.pop(0)

        matrix = [list(map(int, line.split())) for line in lines]

        print(getBrandCount(matrix, m, n))
        lines = []



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很高兴能够参加2023华为OD(B卷)。以下是我的回答: 首先,对于我作为一名技术爱好者和计算科学专业的学生来说,华为OD是我展示自己技能和提升职业能力的绝佳会。我热爱挑战自己,希望能够通过这次来展示我的技术水平和解决问题的能力。 另外,作为一家世界知名的科技公司,华为以其创新能力和领导地位而闻名。参加华为OD,我希望能够学习到尖端的技术和最佳的工程实践。通过与华为的工程师们交流和学习,我相信我将能够进一步提升自己,掌握更多的技术和知识。 此外,参加华为OD也是为了追求个人职业发展的会。华为作为一家全球性的科技公司,有广阔的市场和众多的职业发展会。通过参加华为OD,我希望能够获得华为的认可,并有会加入华为,与卓越的团队一起工作,共同推动公司的发展和创新。 最后,我相信参加华为OD将是一次富有挑战性和有意义的经历。我会认真准备,研究和了解华为的相关业务和技术要求。我相信通过自己的努力和准备,我将能够展现出自己的实力和能力,为华为做出贡献。 总而言之,参加2023华为OD(B卷)对我而言是一个重要的会。我将全力以赴,准备充分,希望在中有出色的表现。我相信通过这次,我将能够展现自己的能力,进一步提升自己,并为华为的发展贡献力量。 ### 回答2: 2023年华为OD(B卷)是华为公司在2023年举行的一次线上。作为华为公司的OD,它将通过互联网的方式进行远程评估,为应聘者提供了参与华为招聘的会。 华为OD(B卷)相对于其他卷别可能会有一些特殊设计或者难度更高的问题。应聘者需要准备好面对各种类型的算法和编程问题,以及一些与华为相关的项目经验。 首先,准备方面,应聘者需掌握基本的数据结构和算法,熟悉常见的算法题型,如搜索、排序、动态规划等。此外,对于华为相关的项目和技术,应聘者需要了解并掌握相关的核心知识和实践经验。 其次,在过程中,要注意时间的合理安排和控制。通常时间较紧,应聘者需要快速理解问题,思考解决方案,并高效地实现代码。同时,要注重代码的可读性和优化,保证代码的正确性和效率。 最后,在OD结束后,应聘者还可以了解并掌握自己在中的不足之处,进一步提升自己的技术能力。同时,可以多关注和了解一些与华为相关的技术和行业动态,为今后的发展做好准备。 总之,参加2023华为OD(B卷)是一次宝贵的会,应聘者需要提前做好充分的准备,掌握技术知识和项目经验,合理安排时间,在中发挥自己的优势,同时也要及时总结经验教训,为未来的发展做好准备。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值