伴学笔记之题解2| 豆包MarsCode AI刷题

72 阅读3分钟

题目解析

题目要求我们在二维平面上对给定的靶子使用最少次暴雨梨花针(垂直射击)来覆盖所有靶子。
每个靶子是一条垂直于 X 轴的线段,需要计算所有靶子最少需要多少次垂直射击,最终结果对 P 取模。


解题思路

1. 问题建模

  • 每个靶子表示为一条线段:[xleft,xright][x_{\text{left}}, x_{\text{right}}]
  • 一次射击对应一条垂直射线 x = c,只要该射线穿过靶子的范围,就能击中该靶子。

问题转换为:

  • 在二维平面上找到最少数量的垂直射线,使得每条射线可以覆盖尽可能多的靶子。

2. 贪心算法

核心思想是使用区间覆盖的贪心策略:

  1. 将所有靶子按照其 xrightx_{\text{right}}(右端点)从小到大排序。
  2. 使用贪心策略选择最靠右的未覆盖靶子的 xrightx_{\text{right}} 作为射击点。
  3. 继续处理剩余未覆盖的靶子,重复上述操作。

3. 算法步骤

  1. 输入解析:读取靶子信息,提取每个靶子的区间范围[xleft,xright][x_{\text{left}}, x_{\text{right}}]

  2. 排序:按照 xrightx_{\text{right}} 进行升序排序。

  3. 贪心选择射击点

    • 选择当前最靠右的xrightx_{\text{right}} 作为射击点,覆盖尽可能多的靶子。
    • 将被覆盖的靶子从列表中移除。
  4. 结果取模:将总射击次数对 P 取模,输出结果。


代码实现

Python 实现

def min_shots(k, p, targets):
    # 提取区间并按 x_right 排序
    intervals = sorted(targets, key=lambda x: x[1])
    
    # 记录最少射击次数
    shots = 0
    last_shot = float('-inf')  # 上一次射击点
    
    for interval in intervals:
        x_left, x_right, _ = interval
        # 如果当前区间未被覆盖
        if last_shot < x_left:
            shots += 1       # 需要新射击
            last_shot = x_right  # 更新射击点为当前区间的右端点
    
    # 返回结果对 P 取模
    return shots % p

# 测试样例
print(min_shots(4, 100, [[10, 26, 3], [4, 8, 29], [1, 5, 8], [9, 9, 9]]))  # 输出: 3
print(min_shots(3, 100, [[10, 26, 3], [4, 8, 29], [1, 5, 8]]))            # 输出: 2
print(min_shots(5, 100, [[5, 15, 5], [1, 2, 3], [20, 25, 2], [6, 18, 2], [30, 40, 1]]))  # 输出: 4
print(min_shots(2, 100, [[0, 10, 5], [15, 20, 3]]))                       # 输出: 2
print(min_shots(6, 100, [[3, 8, 10], [5, 10, 12], [1, 3, 14], [15, 18, 10], [20, 25, 10], [8, 12, 10]]))  # 输出: 4

示例解析

示例 1

输入:k=4,p=100,targets=[[10,26,3],[4,8,29],[1,5,8],[9,9,9]k = 4, p = 100, \text{targets} = [[10, 26, 3], [4, 8, 29], [1, 5, 8], [9, 9, 9]]

靶子区间:

targets=[(10,26),(4,8),(1,5),(9,9)]\text{targets} = [(10, 26), (4, 8), (1, 5), (9, 9)]

排序后:

sorted targets=[(1,5),(4,8),(9,9),(10,26)]\text{sorted targets} = [(1, 5), (4, 8), (9, 9), (10, 26)]

贪心选择射击点:

  1. 选择 x = 5,覆盖第一个区间。
  2. 选择 x = 9,覆盖第二和第三个区间。
  3. 选择 x = 26,覆盖第四个区间。

最少射击次数为 33。


复杂度分析

  1. 时间复杂度

    • 排序时间复杂度为 (klogk)(k \log k),其中 kk 是靶子的数量。
    • 遍历区间时间复杂度为 O(k)O(k)
    • 总体时间复杂度为 O(klogk)O(k \log k)
  2. 空间复杂度

    • 只需额外存储排序后的区间列表,空间复杂度为O(k)O(k)

总结

本题核心是将射击问题转化为区间覆盖问题,通过贪心策略选择最优射击点,实现效率最高的解决方案。