AI刷题65题 | 豆包Marscode AI刷题

98 阅读3分钟

题目介绍

转世之前的唐三,身处唐门。因为是外门弟子,只能通过自学提升武艺,唐三在藏书阁找到了一本介绍暴雨梨花针的古籍。暴雨梨花针:最强单体攻击的绝世暗器,位于一条直线上的所有目标绝无生还可能。但是由于暴雨梨花针十分稀缺,唐三在练习时必须尽可能节约。靶子(二维平面中的一条线)宽度不一,唐三只能朝垂直于 X 轴的方向发射暴雨梨花针,每个靶子所处的位置用(x_left,x_right,y)来表示,请问:给定靶子所处的坐标,唐三最少可以用多少暴雨梨花针击中所有靶子(打到靶子端点也算击中)。

输入格式 第一行两个整数 K,P(只是用来取整,取为 100);表示 K 个靶子 后面 K 行,每行三个整数,分别表示靶子所在的坐标(x_left,x_right,y)

输出格式 输出一个整数,结果为:暴雨梨花针最少数量 % P

题目分析

如图,唐三在横轴的位置,可以向xy区域内长短不一的线段垂直发射暴雨梨花针射线,射线穿过的地方都视为击中。

image.png 那么我们模拟有一条垂直于x轴的射线从左到右扫描一遍整个区域,因为要打到所有靶子,所以扫描一遍的时间要"击穿"所有的线段,而击穿一条线段最晚的时间就是到达它的末端点(即右端点)。因此为了尽可能一次性击穿多的线段,射线最远可以移动到距离它最近的线段的右端点的位置,在这里发射。接着再到达倒数第二近的右端点再次发射,以此类推。 image.png 所以这其实是一个区间覆盖问题

靶子坐标:靶子的位置给定为 (x_left, x_right, y),其中 x_left 和 x_right 是靶子左右两端的 X 坐标,y 是靶子所处的 Y 坐标,Y 坐标不重要,因为我们只关心 X 轴上的区间。

目标:对于给定的多个靶子区间 [x_left, x_right],我们需要找到最少的垂直线(即 X 坐标上的点),使得这些垂直线能够覆盖所有靶子的区间。

解决思路: 将所有靶子的区间按照右端点排序,然后按照贪心策略选择尽量多的区间能够被一根垂直线覆盖。 从最小的右端点开始放置垂直线,并且每次贪心地选择能够覆盖的最大范围的区间。

代码:

int solution(int k, int p, std::vector<std::vector<int>> target) {
    // 按靶子右端点排序,贪心算法的基础
    std::sort(target.begin(), target.end(), [](const std::vector<int>& a, const std::vector<int>& b) {
        return a[1] < b[1];  // 按右端点升序排序
    });

    int arrowCount = 0;
    int lastArrowPos = -1;

    for (const auto& t : target) {
        int x_left = t[0], x_right = t[1];
        // 如果当前靶子无法被之前的箭覆盖,则需要新的箭
        if (lastArrowPos < x_left) {
            lastArrowPos = x_right; // 在当前区间的右端点放置一根箭
            ++arrowCount;
        }
    }

    // 返回结果,箭的数量对P取模
    return arrowCount % p;
}

总结

这个题目让我学会了问题转化的思想,将具体场景先简化为数学模型,能更清楚的找到解决问题的思路。