AI识别面板指示灯排序方法:先行后列规则详解与示例

题目描述

AI识别面板指示灯排序方法:先行后列规则详解与示例

AI 察觉到面板上存在着 N 个指示灯,这里的 N 满足 1 小于等于 N 且 N 小于等于 100。这些指示灯的大小是相同的,并且任意两个指示灯之间不存在重叠的情况。

因为 AI 存在识别误差,每次识别到的指示灯位置或许会有所不同,会用 4 个坐标值来描述 AI 所识别的指示灯的大小和位置,分别是左上角的 x1、y1 以及右下角的 x2、y2。

[id_759590875]

每次从尚未排序的灯中挑选出最高的灯作为基准灯,接着找出与该基准灯属于同一行的所有灯并对其进行排序。当两个灯的高低偏差不超过灯半径时,就判定这两个灯属于同一行,也就是两个灯坐标的差小于或等于灯高度的一半。输入描述

第一行为N,表示灯的个数

接下来N行,每行为1个灯的坐标信息,格式为:

编号 x1 y1 2 y2

输出描述

排序后的编号列表,编号之间以空格分隔

示例1

输入

5
1 0 0 2 2
2 6 1 8 3
3 3 2 5 4
5 5 4 7 6
4 0 4 2 6

输出

1 2 3 4 5

解题思路

题目要求对 AI 识别到的多个指示灯编号进行排序,排序需遵循以下规则:

识别灯的位置:每个指示灯的坐标信息包含了左上角的坐标(x1, y1)以及右下角的坐标(x2, y2),这就构成了灯的边界矩形。灯的位置是由左上角的 y1 高度来定义的,y1 越小,灯就越靠上。排序的规则如下:排序需按行顺序进行。具体方法为:先找出尚未排序的灯中最高的灯,将其作为基准灯,接着找出与该基准灯处于同一行的所有灯。输出格式:依照上述排序后的编号顺序把编号输出出来,编号之间以空格进行分隔。例如进行解析。

给定输入:

5
1 0 0 2 2
2 6 1 8 3
3 3 2 5 4
5 5 4 7 6
4 0 4 2 6

按照题意分析和排序步骤如下:

最终输出结果为:

1 2 3 4 5

Java

引入 Java 中的优先队列类 PriorityQueue 。
import java.util.Comparator;
import java.util.Scanner;
以下是改写后的句子:引入了 Java 中的用于字符串连接的类 StringJoiner 。
public class Main {
公共静态的 void 主函数(String 类型的数组 args)。 主函数用于程序的入口点,在其中可以执行各种操作和逻辑。它接收命令行参数 args 作为输入,并根据这些参数进行相应的处理。 通常在这个函数中会初始化程序的环境、创建对象、调用其他函数等操作,以启动整个程序的运行。
创建一个 Scanner 对象,名为 sc,它用于从 System.in 中获取输入。
获取输入的灯的数量,将输入的字符串通过 Integer.parseInt 方法转换为整数赋值给变量 n
        PriorityQueue pqY = new PriorityQueue<>使用 Comparator.comparingInt 方法,该方法接受一个函数式接口参数 l -> l.y,通过这个函数式接口按 y 坐标进行排序
        // 读取灯的数据并添加到优先队列
        for (int i = 0; i < n; i++) {
            String[] data = sc.nextLine().split(" "); // 使用 split 分割输入行
            int id = Integer.parseInt(data[0]);
            int x1 = Integer.parseInt(data[1]);
            int y1 = Integer.parseInt(data[2]);
            int x2 = Integer.parseInt(data[3]);
            int y2 = Integer.parseInt(data[4]);
            int cx = (x1 + x2) / 2; // 中心x坐标
            int cy = (y1 + y2) / 2; // 中心y坐标
    整数 rad 等于 x2 减去 x1 的结果再除以 2 ;这是半径的值 。
            pqY.offer(new Light(id, cx, cy, rad));
        }
        StringJoiner result = new StringJoiner(" ");
        PriorityQueue pqX = new PriorityQueue<>使用 Comparator 的 comparingInt 方法,传入一个 lambda 表达式 l -> l.x,用于按 x 坐标进行排序
        while (!pqY.isEmpty()) {
当前基准灯的光反射值为 pqY.poll()。
            pqX.offer(ref); // 添加基准灯到当前行
            // 查找并添加同一行的灯
当 pqY 不为空且 pqY 队列头部元素的 y 坐标与 ref.y 的绝对值满足一定条件时<= ref.r) {
                pqX.offer(pqY.poll());
            }
            // 输出当前行的灯编号
            while (!pqX.isEmpty()) {
                result.add(String.valueOf(pqX.poll().id)); // 按x坐标顺序输出同一行的灯编号
            }
        }
        System.out.println(result.toString()); // 输出结果
    }
}
class Light {
    int id;
    int x;
    int y;
    int r;
    public Light(int id, int x, int y, int r) {
        this.id = id;
        this.x = x;
        this.y = y;
        this.r = r;
    }
}

Python

import heapq
灯对象包含以下内容:id 、x 坐标、y 坐标以及半径 r 。
class Light:
初始化自身,包含 id、x、y、r 这些参数。
        self.id = id
        self.x = x
        self.y = y
        self.r = r
    # 定义排序规则:按 y 坐标排序
    def __lt__(self, other):
        return self.y < other.y
def main():
    n = int(input())  # 读取灯的数量
    pqY = []  # 按 y 坐标排序的优先队列(最小堆)
    # 读取灯的数据并添加到优先队列
    for _ in range(n):
        data = list(map(int, input().split()))  # 读取一行并分割为整数列表
        id, x1, y1, x2, y2 = data
        cx = (x1 + x2) // 2  # 中心 x 坐标
        cy = (y1 + y2) // 2  # 中心 y 坐标
        rad = (x2 - x1) // 2  # 半径
        heapq.heappush(pqY, Light(id, cx, cy, rad))  # 将灯对象加入到 y 坐标最小堆
    result = []  # 存储最终输出的灯编号
    pqX = []  # 按 x 坐标排序的最小堆
    # 处理每一行灯
    while pqY:
        ref = heapq.heappop(pqY)  # 弹出当前行的基准灯
        heapq.heappush(pqX, ref)  # 将基准灯添加到当前行
        # 查找并添加同一行的灯
        while pqY and abs(pqY[0].y - ref.y) <= ref.r:
            heapq.heappush(pqX, heapq.heappop(pqY))
        # 按 x 坐标顺序输出同一行的灯编号
        while pqX:
            result.append(str(heapq.heappop(pqX).id))
    print(" ".join(result))  # 输出结果
main()

JavaScript

需要引入 readline 模块,其名称为 readline ,通过 require 函数来获取该模块的功能。
创建一个名为 rl 的接口,该接口是通过 readline 创建的。
    input: process.stdin,
    output: process.stdout
});
class Light {
    constructor(id, x, y, r) {
        this.id = id;
        this.x = x;
        this.y = y;
        this.r = r;
    }
}
// 优先队列排序函数,按 y 坐标排序
定义一个名为 yComparator 的函数,该函数接受两个参数 a 和 b,函数体内部是 a 的 y 属性减去 b 的 y 属性的计算式,用于比较两个对象的 y 属性大小。
// 按 x 坐标排序
定义一个名为 xComparator 的函数,该函数接收两个参数 a 和 b,函数内部通过计算 a 的 x 属性值减去 b 的 x 属性值来进行比较。
const main = async () => {
    const input = [];
使用 await 从 rl 中逐行获取 line 。
        input.push(line.trim());
    }
获取输入的第一个元素并将其解析为十进制整数,赋值给变量 n,n 表示灯的数量。
const pqY 是一个用于按 y 坐标进行排序的灯的优先队列,它里面没有元素,初始为空数组。
    // 读取每个灯的坐标
    for (let i = 1; i <= n i const id x1 y1 x2 y2='input[i].split("' .mapnumber const cx='Math.floor((x1' x2 2 x const cy='Math.floor((y1' y2 2 y const rad='Math.floor((x2' - x1 2 pqy.pushnew lightid cx cy rad pqy.sortycomparator pqy y const result='[];' let pqx='[];' x while pqy.length> 0) {
const ref 等于 pqY 进行 shift 操作后的结果;这就是当前行的基准灯。
        pqX.push(ref); // 将基准灯添加到当前行
pqX 按照 x 坐标进行排序;对 pqX 依据 x 坐标进行排序操作;通过 x 坐标对 pqX 进行排序处理;以 x 坐标为依据对 pqX 进行排序;按照 x 坐标的顺序对 pqX 进行排序;依据 x 坐标来对 pqX 进行排序;用 x 坐标对 pqX 实施排序;基于 x 坐标对 pqX 展开排序;以 x 坐标为准则对 pqX 进行排序
        // 查找并添加同一行的灯
当 pqY 的长度大于 0 且 pqY 的第一个元素的 y 坐标与 ref.y 的绝对值<= ref.r pqx.pushpqy.shift pqx.sortxcomparator x while pqx.length> 0) {
首先弹出 pqX 的第一个元素,然后获取该元素的 id 属性并转换为字符串,最后将这个字符串添加到 result 数组中。
        }
    }
console.log(result.join(" ")); 这行代码用于输出最终的结果。
};
main();

C++

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
灯对象结构体,其中包含有 id ,还有 x 坐标,以及 y 坐标,同时包含半径 r 。
struct Light {
    int id, x, y, r;
定义一个名为 Light 的类,该类接受四个参数:id、x、y 和 r。在类的构造函数中,将传入的参数 id 赋值给成员变量 id,将参数 x 赋值给成员变量 x,将参数 y 赋值给成员变量 y,将参数 r 赋值给成员变量 r。
};
// y 坐标排序的比较器
struct CompareY {
定义一个操作符函数,用于比较两个 Light 类型的对象 a 和 b。如果满足特定条件,则返回 true;否则返回 false。
        return a.y > b.y;
    }
};
// x 坐标排序的比较器
struct CompareX {
    bool operator()(const Light& a, const Light& b) {
        return a.x > b.x;
    }
};
int main() {
    int n;
    cin >> n; // 读取灯的数量
    priority_queue按 y 坐标排序的优先队列是 CompareY 且 pqY 与之相关
    // 读取灯的数据并添加到优先队列
    for (int i = 0; i < n i int id x1 y1 x2 y2 cin>> id >> x1 >> y1 >> x2 >> y2;
这就是中心 x 坐标。
中心 y 坐标是通过将 y1 和 y2 相加后再除以 2 得到的,即 int cy = (y1 + y2) / 2;
        int rad = (x2 - x1) / 2; // 半径
pqY 把灯对象加入到了 y 坐标优先队列中,这个灯对象带有 id、cx、cy 和 rad 这些属性。
    }
    stringstream result;
    priority_queue按 x 坐标排序的优先队列是 CompareX> pqX;
    // 处理每一行灯
    while (!pqY.empty()) {
        Light ref = pqY.top();
        pqY.pop();
        pqX.push(ref);
        // 查找并添加同一行的灯
当 pqY 不为空且 pqY 顶部元素的 y 值与 ref.y 的绝对值小于等于 eps 时,执行循环体中的操作,然后弹出 pqY 的顶部元素。<= ref.r) {
            pqX.push(pqY.top());
            pqY.pop();
        }
        // 输出当前行的灯编号
        while (!pqX.empty()) {
            result << pqX.top().id << " ";
            pqX.pop();
        }
    }
    cout << result.str() << endl; // 输出最终结果
    return 0;
}

C语言

#include 
#include 
#include 
#include 
假设最多能有 1000 盏灯;这里定义了 MAX_LIGHTS 为 1000 ;即最多有 1000 盏灯的意思;定义的 MAX_LIGHTS 表示最多的灯的数量为 1000 ;意味着最多有 1000 盏灯;MAX_LIGHTS 被定义为最多有 1000 盏灯的数量;定义的 MAX_LIGHTS 意味着最多可存在 1000 盏灯;最多有 1000 盏灯是通过定义 MAX_LIGHTS 来体现的;定义的 MAX_LIGHTS 是关于最多有 1000 盏灯的设定。
定义一个结构体来表示灯,这个结构体包含灯的 id 、x 坐标、y 坐标以及半径 r 。
typedef struct {
    int id;
    int x;
    int y;
    int r;
} Light;
// 按 y 坐标排序的比较函数,用于 qsort
定义一个比较函数 compareByY,它接受两个 const void* 类型的参数 a 和 b,用于比较两个元素在 y 轴上的大小关系。
首先获取 a 所指向的 Light 结构体中的 y 值,即 ((Light *)a)->y ;然后获取 b 所指向的 Light 结构体中的 y 值,即 ((Light *)b)->y ;最后用获取到的 a 的 y 值减去 b 的 y 值,即 ((Light *)a)->y - ((Light *)b)->y 。
}
// 按 x 坐标排序的比较函数,用于 qsort
定义一个比较函数 compareByX,它接受两个 const void* 类型的参数 a 和 b,用于比较它们的大小。
首先获取指向 a 的 Light 类型指针并解引用,然后获取其 x 属性值;接着获取指向 b 的 Light 类型指针并解引用,再获取其 x 属性值;最后用前一个 x 值减去后一个 x 值。
}
int main() {
    int n; // 灯的数量
存储灯的数组为 Light lights[MAX_LIGHTS];
Light 类型的数组 LightRowLights,其大小为 MAX_LIGHTS,用于存储同一行的灯。
    // 读取灯的数量
    scanf("%d", &n);
    // 读取每个灯的数据
    for (int i = 0; i < n; i++) {
        int id, x1, y1, x2, y2;
        scanf("%d %d %d %d %d", &id, &x1, &y1, &x2, &y2);
        int cx = (x1 + x2) / 2; // 计算中心 x 坐标
        int cy = (y1 + y2) / 2; // 计算中心 y 坐标
        int rad = (x2 - x1) / 2; // 计算半径 r
        lights[i] = (Light){id, cx, cy, rad}; // 将灯信息存入数组
    }
    // 对灯数组按 y 坐标排序
    qsort(lights, n, sizeof(Light), compareByY);
    int result[MAX_LIGHTS]; // 存储结果灯的 ID 的数组
    int resultIndex = 0;    // 结果数组的索引
    int i = 0;
    while (i < n) {
        int rowCount = 0; // 当前行灯的数量
        Light ref = lights[i]; // 基准灯
        rowLights[rowCount++] = ref; // 将基准灯添加到当前行
        i++;
        // 查找并添加同一行的灯(基于 y 坐标和半径范围判断)
        while (i < n && abs(lights[i].y - ref.y) <= ref.r) {
            rowLights[rowCount++] = lights[i];
            i++;
        }
        // 对当前行的灯按 x 坐标排序
        qsort(rowLights, rowCount, sizeof(Light), compareByX);
        // 按顺序将当前行的灯编号添加到结果
        for (int j = 0; j < rowCount; j++) {
            result[resultIndex++] = rowLights[j].id;
        }
    }
    // 输出所有灯的编号
    for (int i = 0; i < resultIndex; i++) {
        printf("%d ", result[i]);
    }
    printf("\n");
    return 0;
}

你可能想看:
« 上一篇
下一篇 »

相关推荐

FreeBasic:强大免费开源的64位basic编译器及应用优势

2025年05月10日

82阅读

脊柱侧弯矫正方法大盘点:运动康复、支具矫正等多种方式

2025年05月09日

88阅读

如何在winForm标题栏去掉标题文字且任务栏图标正常显示

2025年05月09日

86阅读

十一黄金周促销广告词大全,国庆购物狂欢等你来

2025年05月09日

78阅读

关闭快速编辑模式及插入模式,设置控制台指定文字颜色举例

2025年05月09日

63阅读

黄金搭档低糖高钙饮品包装及成分功效全解析,适合人群要知晓

2025年05月09日

91阅读