【华为OD-E卷 - ai面板识别 100分(python、java、c++、js、c)】
题目
AI识别到面板上有N(1 ≤ N ≤ 100)个指示灯,灯大小一样,任意两个之间无重叠。
 由于AI识别误差,每次别到的指示灯位置可能有差异,以4个坐标值描述AI识别的指示灯的大小和位置(左上角x1,y1,右下角x2,y2),
 请输出先行后列排序的指示灯的编号,排序规则:
 每次在尚未排序的灯中挑选最高的灯作为的基准灯, 找出和基准灯属于同一行所有的灯进行排序。两个灯高低偏差不超过灯半径算同一行(即两个灯坐标的差 ≤ 灯高度的一半)
输入描述
- 第一行为N,表示灯的个数 接下来N行,每行为1个灯的坐标信息,格式为:
编号 x1 y1 x2 y2
编号全局唯一 1 ≤ 编号 ≤ 100 0 ≤ x1 < x2 ≤ 1000 0 ≤ y1 < y2 ≤ 1000
输出描述
- 排序后的编号列表,编号之间以空格分隔
用例
用例一:
输入:
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
- 6
输出:
1 2 3 4 5
- 1

python解法
- 解题思路:
- 这段代码的目的是处理一组灯光的位置和大小,并按照特定的规则对这些灯光进行排序。根据给定的灯光的坐标和半径,程序将这些灯光按垂直方向(y坐标)分组,然后在每个组内按水平方向(x坐标)排序,最后输出这些灯光的索引。
具体步骤如下:
输入解析:
首先,读取灯光的数量 n。
 然后,读取每个灯光的坐标和半径信息,使用这些信息创建 Light 类的实例,存储在一个列表 lights 中。
 灯光位置与排序规则:
每个灯光的坐标 (x, y) 是由其给定的两个角的坐标计算得来的:x = (x1 + x2) // 2 和 y = (y1 + y2) // 2。
 灯光的半径 radius 是由给定的两个角的横向距离计算得来的:radius = (x2 - x1) // 2。
 按垂直方向分组:
将所有灯光按照 y 坐标进行排序,确保灯光从上到下排列。
 在排序后的灯光列表中,尝试将尽可能多的灯光分配到同一组中。分组的标准是:当前灯光的 y 坐标与上一灯光的 y 坐标之差小于等于该灯光的半径。
 组内按水平方向排序:
在每一组内,将灯光按 x 坐标从左到右排序。
 输出结果:
输出每一组中灯光的索引,按排序后的顺序输出所有组的灯光索引
# 定义 Light 类来存储灯光的信息
class Light:
    def __init__(self, idx, x1, y1, x2, y2):
        self.idx = idx  # 灯光的索引
        self.x = (x1 + x2) // 2  # 计算灯光的横坐标:两个角的中点
        self.y = (y1 + y2) // 2  # 计算灯光的纵坐标:两个角的中点
        self.radius = (x2 - x1) // 2  # 计算灯光的半径:两个角的横向距离的一半
# 读取输入,获取灯光的数量 n
n = int(input())
# 读取每个灯光的信息,创建 Light 对象并存入列表 lights
lights = [Light(*map(int, input().split())) for _ in range(n)]
# 按照灯光的 y 坐标进行排序
lights.sort(key=lambda l: l.y)
# 初始化结果列表和临时行列表
result = []
temp_row = []
# 初始的基准灯光是排序后的第一个灯光
base_light = lights[0]
temp_row.append(base_light)
# 遍历灯光列表,从第二个灯光开始
for i in range(1, len(lights)):
    light = lights[i]
    # 如果当前灯光与基准灯光的纵坐标差小于等于基准灯光的半径,属于同一行
    if light.y - base_light.y <= base_light.radius:
        temp_row.append(light)
    else:
        # 如果当前灯光不在同一行,先按 x 坐标排序并加入结果
        temp_row.sort(key=lambda l: l.x)
        result.extend([l.idx for l in temp_row])  # 将该行灯光的索引加入结果列表
        temp_row.clear()  # 清空临时行
        base_light = light  # 更新基准灯光为当前灯光
        temp_row.append(base_light)  # 将当前灯光加入新的行
# 如果最后一行还有灯光,处理这一行
if temp_row:
    temp_row.sort(key=lambda l: l.x)  # 按 x 坐标排序
    result.extend([l.idx for l in temp_row])  # 将该行灯光的索引加入结果列表
# 输出结果,灯光的索引以空格分隔
print(" ".join(map(str, result)))
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
java解法
- 解题思路
- 这段代码的目标是根据给定的灯光信息(每个灯光的坐标和半径),按照垂直方向分组灯光,并在每个组内按水平方向排序,最终输出每个灯光的索引。
具体步骤如下:
输入解析:
首先读取灯光的数量 n。
 对于每个灯光,读取其编号 id、两个角点的坐标 (x1, y1) 和 (x2, y2),然后根据这些信息计算出灯光的中心坐标 (x, y) 和半径 r。
 灯光排序:
通过 y 坐标对所有灯光进行排序,这样可以按垂直方向将灯光分为不同的组。
 分组灯光:
遍历排序后的灯光列表,将 y 坐标差值小于等于当前灯光半径的灯光归为同一组。每一组的灯光都需要按照 x 坐标进行排序。
 输出排序后的灯光编号:
对每一组灯光,根据 x 坐标排序并输出其编号。每组灯光的编号按从左到右的顺序输出。
 最终输出:
输出所有组的灯光编号,确保它们的顺序是正确的
import java.util.*;
public class Main {
    
    public static void main(String[] args) {
        // 创建 Scanner 对象来读取输入
        Scanner scanner = new Scanner(System.in);
        
        // 读取灯光的数量
        int n = scanner.nextInt();
        
        // 创建一个灯光数组来存储所有的灯光
        Light[] lights = new Light[n];
        // 循环读取每个灯光的信息
        for (int i = 0; i < n; i++) {
            int id = scanner.nextInt();  // 灯光编号
            int x1 = scanner.nextInt();  // 第一个角的 x 坐标
            int y1 = scanner.nextInt();  // 第一个角的 y 坐标
            int x2 = scanner.nextInt();  // 第二个角的 x 坐标
            int y2 = scanner.nextInt();  // 第二个角的 y 坐标
            
            // 计算灯光的中心坐标 (x, y) 和半径 r
            lights[i] = new Light(id, (x1 + x2) / 2, (y1 + y2) / 2, (x2 - x1) / 2);
        }
        // 调用 determineOrder 方法得到最终的排序结果并输出
        System.out.println(determineOrder(lights));
    }
    // 该方法用于确定灯光的排序结果
    public static String determineOrder(Light[] lights) {
        // 按照 y 坐标对灯光进行排序
        Arrays.sort(lights, Comparator.comparingInt(light -> light.y));
        // 使用 StringBuilder 来高效构建结果字符串
        StringBuilder result = new StringBuilder();
        
        // 创建一个 List 用于存储当前行的灯光
        List<Light> sameRow = new ArrayList<>();
        
        // 将第一个灯光设为基准灯光
        Light reference = lights[0];
        sameRow.add(reference);
        // 遍历剩下的灯光
        for (int i = 1; i < lights.length; i++) {
            Light current = lights[i];
            
            // 如果当前灯光的 y 坐标与基准灯光的 y 坐标差值小于等于基准灯光的半径,
            // 说明它们可以在同一行,加入同一行的灯光列表
            if (current.y - reference.y <= reference.r) {
                sameRow.add(current);
            } else {
                // 如果当前灯光不在同一行,先对当前行的灯光按 x 坐标排序
                sameRow.sort(Comparator.comparingInt(light -> light.x));
                
                // 将当前行的所有灯光编号加入结果字符串
                for (Light light : sameRow) {
                    result.append(light.id).append(" ");
                }
                
                // 清空当前行的灯光列表
                sameRow.clear();
                
                // 更新基准灯光为当前灯光,并开始新的行
                reference = current;
                sameRow.add(reference);
            }
        }
        // 如果最后一行灯光还没有被处理,进行处理
        if (!sameRow.isEmpty()) {
            sameRow.sort(Comparator.comparingInt(light -> light.x));  // 按 x 坐标排序
            for (Light light : sameRow) {
                result.append(light.id).append(" ");
            }
        }
        // 返回最终结果字符串,去掉尾部的多余空格
        return result.toString().trim();
    }
}
// 定义 Light 类来存储每个灯光的信息
class Light {
    int id;  // 灯光编号
    int x;   // 灯光的 x 坐标(中心)
    int y;   // 灯光的 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;
    }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
C++解法
- 解题思路
更新中
- 1
C解法
输入解析:
每个灯光的编号 id 和它的两个角点坐标 (x1, y1) 和 (x2, y2),程序需要通过这些数据计算出灯光的中心坐标 (x, y) 和半径 r。
 排序规则:
首先根据 y 坐标对所有灯光进行排序。
 然后根据灯光的 y 坐标差值判断是否处于同一行,如果是,则按 x 坐标排序;如果不是,则将当前行的灯光按 x 坐标输出。
 分组灯光:
程序将灯光分为几组:如果灯光 y 坐标差值小于等于当前灯光的半径,则认为它们在同一行。
 对每行内的灯光进行 x 坐标排序,然后输出它们的编号
#include - 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
JS解法
灯光根据 y 坐标排序,若 y 坐标差距小于等于某个基准灯光的半径 r,则认为这些灯光在同一行。
 同一行内的灯光按照 x 坐标进行排序,然后输出它们的编号。
 如果灯光属于不同的行,则按 y 坐标分组并按 x 坐标排序。
const readline = require("readline");
// 创建读取接口
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});
let data = []; // 存储输入数据
let numberOfLights; // 灯光数量
// 监听每行输入
rl.on("line", (line) => {
    data.push(line); // 将每行输入存储到 data 数组中
    if (data.length === 1) {
        numberOfLights = parseInt(data[0]); // 第一行是灯光数量,转换为数字
    }
    // 当读取到足够的输入数据后,开始处理
    if (numberOfLights && data.length === numberOfLights + 1) {
        data.shift(); // 删除第一行(灯光数量)
        // 处理灯光数据
        const lights = data.map((str) => {
            const [id, x1, y1, x2, y2] = str.split(" ").map(Number);
            return { id, midX: (x1 + x2) / 2, midY: (y1 + y2) / 2, rad: (x2 - x1) / 2 };
        });
        // 输出处理结果
        console.log(computeOrder(lights));
        // 清空数据,准备下一个测试用例
        data = [];
    }
});
// 计算灯光的顺序
function computeOrder(lightArray) {
    // 按照 midY (y 坐标) 排序
    lightArray.sort((lightA, lightB) => lightA.midY - lightB.midY);
    const finalOrder = []; // 存储最终的灯光编号顺序
    let rowLights = []; // 存储当前行的灯光
    let currentLight = lightArray[0]; // 基准灯光为第一个灯光
    rowLights.push(currentLight); // 将基准灯光加入当前行
    // 遍历所有灯光
    for (let i = 1; i < lightArray.length; i++) {
        const nextLight = lightArray[i];
        // 如果当前灯光和基准灯光的 y 坐标差值小于等于基准灯光的半径,则认为它们在同一行
        if (nextLight.midY - currentLight.midY <= currentLight.rad) {
            rowLights.push(nextLight); // 将灯光加入当前行
        } else {
            // 当前灯光与基准灯光不在同一行,输出当前行的灯光编号并重置
            finalizeRow(rowLights, finalOrder);
            rowLights = [nextLight]; // 新行开始,加入当前灯光
            currentLight = nextLight; // 更新基准灯光为当前灯光
        }
    }
    // 处理最后一行
    if (rowLights.length > 0) {
        finalizeRow(rowLights, finalOrder);
    }
    return finalOrder.join(" "); // 返回最终的灯光编号顺序
}
// 输出当前行的灯光编号,并按 x 坐标排序
function finalizeRow(row, result) {
    row.sort((a, b) => a.midX - b.midX) // 按 x 坐标升序排序
        .forEach((light) => result.push(light.id)); // 将排序后的灯光编号加入结果数组
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
注意:
如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
 解题不易,如对您有帮助,欢迎点赞/收藏
 
                                    
评论记录:
回复评论: