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
。
1 | 1 | 1 | 1 | 1 | 1 |
1 | 5 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 |
5 | 1 | 1 | 1 | 1 | 1 |
5 | 1 | 1 | 1 | 1 | 1 |
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,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 = []