华为OD机试真题---ai面板识别

一、题目描述

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

三、输出描述

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

示例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

在这里插入图片描述

四、代码实现



import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

/**
 * @author code5bug
 */

class Light {
    int no, x1, y1, x2, y2;
    int height;

    public Light(int no, int x1, int y1, int x2, int y2) {
        this.no = no;
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.height = y2 - y1;
    }

    public int getHeight() {
        return height;
    }

    public int getX1() {
        return x1;
    }

    @Override
    public String toString() {
        return "Light{" +
                "no=" + no +
                ", x1=" + x1 +
                ", y1=" + y1 +
                ", x2=" + x2 +
                ", y2=" + y2 +
                ", height=" + height +
                '}';
    }
}

public class LightSorter {
    public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int N = scanner.nextInt();

    if (N <= 0) {
        System.out.println("Invalid input: N must be greater than 0.");
        return;
    }

    List<Light> lights = new ArrayList<>();
    for (int i = 0; i < N; i++) {
        int no = scanner.nextInt();
        int x1 = scanner.nextInt();
        int y1 = scanner.nextInt();
        int x2 = scanner.nextInt();
        int y2 = scanner.nextInt();

        if (no <= 0 || x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0) {
            System.out.println("Invalid input: All values must be non-negative and no must be greater than 0.");
            return;
        }
        lights.add(new Light(no, x1, y1, x2, y2));
    }

    // 指定编号的指示灯是否已选择
    boolean[] selected = new boolean[N + 1];
    // 排序后的编号列表
    List<Integer> sortedRst = new ArrayList<>();

    while (true) {
        // 在尚未排序的灯中挑选最高的灯作为的基准灯
        Light baseLight = null;
        for (Light light : lights) {
            if (selected[light.no]) continue;
            if (baseLight == null || baseLight.y1 > light.y1) {
                baseLight = light;
            }
        }

        if (baseLight == null) break;

        // 找出和基准灯属于同一行所有的灯进行排序。两个灯高低偏差不超过灯半径算同一行
        // (即两个灯坐标的差  灯高度的一半)。
        List<Light> lineLights = new ArrayList<>();
        // 灯半径
        double lightRadius = baseLight.getHeight() / 2.0;
        for (Light light : lights) {
            if (!selected[light.no] && Math.abs(baseLight.y1 - light.y1) <= lightRadius) {
                lineLights.add(light);
            }
        }

        // 对同一行的灯进行排序,根据x1坐标
        lineLights.sort(Comparator.comparingInt(Light::getX1));

        // 将排序后的灯编号加入结果列表,并标记为已选择
        for (Light light : lineLights) {
            sortedRst.add(light.no);
            selected[light.no] = true;
        }
    }

    // 输出排序后的灯编号
    for (int no : sortedRst) {
        System.out.print(no + " ");
    }
}

}

五、运行示例解析

输入

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、读取输入:

  • 第一行输入 5 表示有 5 个灯。
  • 接下来的 5 行分别表示每个灯的编号 no 和坐标 (x1, y1, x2, y2)。
    2、初始化灯列表:
  • 创建一个 List 来存储所有灯的信息。
  • 读取每个灯的信息并创建 Light 对象,添加到列表中。
    3、输入验证:
  • 检查 N 是否大于 0。
  • 检查每个灯的编号 no 是否大于 0,坐标 x1, y1, x2, y2 是否非负。
    4、初始化辅助数据结构:
  • boolean[] selected 用于记录每个灯是否已被选择。
  • List sortedRst 用于存储排序后的灯编号。
    5、主循环:
  • 在每次循环中,找到尚未选择的最低的灯作为基准灯。
  • 找出与基准灯在同一行的所有灯(高度偏差不超过灯半径)。
  • 对同一行的灯按 x1 坐标进行排序。
  • 将排序后的灯编号加入结果列表,并标记为已选择。
    6、输出结果:
  • 输出排序后的灯编号。
具体执行过程

1、读取输入并初始化灯列表:

   List<Light> lights = new ArrayList<>();
   lights.add(new Light(1, 0, 0, 2, 2)); // Light{no=1, x1=0, y1=0, x2=2, y2=2, height=2}
   lights.add(new Light(2, 6, 1, 8, 3)); // Light{no=2, x1=6, y1=1, x2=8, y2=3, height=2}
   lights.add(new Light(3, 3, 2, 5, 4)); // Light{no=3, x1=3, y1=2, x2=5, y2=4, height=2}
   lights.add(new Light(5, 5, 4, 7, 6)); // Light{no=5, x1=5, y1=4, x2=7, y2=6, height=2}
   lights.add(new Light(4, 0, 4, 2, 6)); // Light{no=4, x1=0, y1=4, x2=2, y2=6, height=2}
   

2、第一次循环:

  • 基准灯:Light{no=1, x1=0, y1=0, x2=2, y2=2, height=2}
  • 同一行的灯:Light{no=1, x1=0, y1=0, x2=2, y2=2, height=2}
  • 排序后:Light{no=1, x1=0, y1=0, x2=2, y2=2, height=2}
  • 结果列表:[1]
  • 标记 selected[1] = true

3、第二次循环:

  • 基准灯:Light{no=2, x1=6, y1=1, x2=8, y2=3, height=2}
  • 同一行的灯:Light{no=2, x1=6, y1=1, x2=8, y2=3, height=2}
  • 排序后:Light{no=2, x1=6, y1=1, x2=8, y2=3, height=2}
  • 结果列表:[1, 2]
  • 标记 selected[2] = true

4、第三次循环:

  • 基准灯:Light{no=3, x1=3, y1=2, x2=5, y2=4, height=2}
  • 同一行的灯:Light{no=3, x1=3, y1=2, x2=5, y2=4, height=2}
  • 排序后:Light{no=3, x1=3, y1=2, x2=5, y2=4, height=2}
  • 结果列表:[1, 2, 3]
  • 标记 selected[3] = true

5、第四次循环:

  • 基准灯:Light{no=5, x1=5, y1=4, x2=7, y2=6, height=2}
  • 同一行的灯:Light{no=5, x1=5, y1=4, x2=7, y2=6, height=2}, Light{no=4, x1=0, y1=4, x2=2, y2=6, height=2}
  • 排序后:Light{no=4, x1=0, y1=4, x2=2, y2=6, height=2}, Light{no=5, x1=5, y1=4, x2=7, y2=6, height=2}
  • 结果列表:[1, 2, 3, 4, 5]
  • 标记 selected[4] = true, selected[5] = true

6、输出结果:

1 2 3 4 5

六、解析步骤

  1. 初始化

    • 读取整数N(灯的数量)。
    • 创建一个Light对象的列表lights
    • 创建一个布尔数组selected,用于跟踪哪些灯已经被排序(或选中),长度为N + 1(因为灯编号从1开始)。
    • 创建一个整数列表sortedRst,用于存储排序后的灯编号。
  2. 读取灯的数据

    • 读取每个灯的编号(no)、左上角坐标(x1, y1)和右下角坐标(x2, y2),并创建Light对象添加到lights列表中。
    • 检查输入的有效性(确保所有值都是非负的,且编号大于0)。在本例中,所有输入都是有效的。
  3. 排序过程

    • 使用一个while循环来重复以下步骤,直到所有灯都被排序(即baseLightnull)。
    • 在尚未排序的灯中,找到y1坐标最小的灯作为基准灯baseLight
    • 计算基准灯的height(即y2 - y1)和lightRadius(即高度的一半)。
    • 创建一个新列表lineLights,用于存储与基准灯在同一行的所有灯。
    • 遍历所有灯,如果灯未被选中且其y1坐标与基准灯的y1坐标之差不超过lightRadius,则将该灯添加到lineLights列表中。
    • lineLights列表中的灯按照x1坐标进行排序。
    • 将排序后的灯编号添加到sortedRst列表中,并将这些灯在selected数组中标记为已选中。
  4. 输出排序后的灯编号

    • 遍历sortedRst列表,输出每个灯的编号。

七、注意

  • 在我的代码中,实际上是在找y1最大的灯作为基准灯,而不是最小的。如果您的意图是找最小的,需要反转比较条件(即baseLight == null || baseLight.y1 < light.y1)。
  • 在本例中,由于所有灯的y1坐标都是唯一的,因此没有真正的“同一行”灯需要处理。但是,如果y1坐标不是唯一的,并且两个灯的y1坐标之差在lightRadius之内,那么它们将被视为同一行并进行排序。
  • 性能优化:可以使用优先队列(PriorityQueue)来管理未选择的灯,提高查找基准灯的效率。
分披萨 题目描述 在给定 m个人的情况下,有 n块比萨。每块比萨都有一个分数。我们希望将比萨分配给每个人,使得每个人得分尽可能多。分数可以为 0。 例如,在给定 3 个人和 3 块比萨的情况下,比萨的得分分别为 5, 4, 7,我们可以将比萨分配为: (5)(4)(7),以便每个人分别得到 5, 4, 7 分。 给定 m 个人和 n 块比萨,每块比萨的得分以及每个人对比萨的偏好 (可能有中性,喜欢或者讨厌),你的任务是计算每个人得到的最大分数。 输入格式 输入包含多组测数据。 每组测数据的第一行包含两个整数 n(1≤n≤1000) 和 m(1≤m≤100) — 分别表示比萨的数量和人数。第二行包含 n 个整数 a1,a2…an(1ai1000) — 表示每块比萨的分数。接下来的 m 行每行包含 n 个整数 b1,b2…bn(1≤bi≤1) — 表示每个人喜欢(1),中性(0)或者讨厌(1)每块比萨。 输入保证对于每组测数据至少存在一个人喜欢比萨。 当 n = m = 0 时,表示输入结束。 输出格式 对于每组测数据,输出 m 行。每行包含一个整数,表示每个人得到的最大分数。 样例输入 3 3 5 4 7 1 0 -1 0 1 0 1 0 0 3 3 4 7 8 -1 0 1 1 -1 0 1 0 0 样例输出 5 4 7 4 7 8 ```python # 代码: while True: n, m = list(map(int, input().split())) if n == 0 and m == 0: break pizzas = list(map(int, input().split())) preferences = [list(map(int, input().split())) for _ in range(m)] scores = [0] * m for i in range(n): max_score = 0 for j in range(m): if preferences[j][i] == 1: max_score = max(max_score, pizzas[i]) elif preferences[j][i] == 0: max_score = max(max_score, pizzas[i] // 2) for j in range(m): if preferences[j][i] == 1 or (preferences[j][i] == 0 and max_score == pizzas[i] // 2): scores[j] += max_score for score in scores: print(score) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值