题目解析
题目要求我们在二维平面上对给定的靶子使用最少次暴雨梨花针(垂直射击)来覆盖所有靶子。
每个靶子是一条垂直于 X 轴的线段,需要计算所有靶子最少需要多少次垂直射击,最终结果对 P 取模。
解题思路
1. 问题建模
- 每个靶子表示为一条线段:。
- 一次射击对应一条垂直射线 x = c,只要该射线穿过靶子的范围,就能击中该靶子。
问题转换为:
- 在二维平面上找到最少数量的垂直射线,使得每条射线可以覆盖尽可能多的靶子。
2. 贪心算法
核心思想是使用区间覆盖的贪心策略:
- 将所有靶子按照其 (右端点)从小到大排序。
- 使用贪心策略选择最靠右的未覆盖靶子的 作为射击点。
- 继续处理剩余未覆盖的靶子,重复上述操作。
3. 算法步骤
-
输入解析:读取靶子信息,提取每个靶子的区间范围。
-
排序:按照 进行升序排序。
-
贪心选择射击点:
- 选择当前最靠右的作为射击点,覆盖尽可能多的靶子。
- 将被覆盖的靶子从列表中移除。
-
结果取模:将总射击次数对 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
输入:]
靶子区间:
排序后:
贪心选择射击点:
- 选择 x = 5,覆盖第一个区间。
- 选择 x = 9,覆盖第二和第三个区间。
- 选择 x = 26,覆盖第四个区间。
最少射击次数为 33。
复杂度分析
-
时间复杂度:
- 排序时间复杂度为 ,其中 kk 是靶子的数量。
- 遍历区间时间复杂度为 。
- 总体时间复杂度为 。
-
空间复杂度:
- 只需额外存储排序后的区间列表,空间复杂度为。
总结
本题核心是将射击问题转化为区间覆盖问题,通过贪心策略选择最优射击点,实现效率最高的解决方案。