问题描述
一条无限长的直线上分布着一些机器人和墙壁。给定整数数组 robots、distance 和 walls:
robots[i]是第 i 个机器人的位置。distance[i]是第 i 个机器人的子弹最大射程。walls[j]是第 j 堵墙的位置。
每个机器人有一颗子弹,可以向左或向右发射,最远距离为 distance[i]。子弹会摧毁其射程内路径上的每一堵墙。但机器人是固定的障碍物:如果子弹在到达墙壁前击中另一个机器人,它会立即在该机器人处停止,无法继续前进。
返回机器人可以摧毁墙壁的最大数量。注意:墙壁和机器人可能在同一位置;该位置的墙壁可以被该位置的机器人摧毁。机器人不会被子弹摧毁。
示例:
输入:robots = [4, 10], distance = [3, 5], walls = [1, 5, 7, 10]
输出:3
解释:机器人 0 向左射击覆盖 [1, 4],摧毁墙 1;机器人 1 向左射击覆盖 [5, 10],摧毁墙 5 和 7(墙 10 被自身挡住或视为已处理)。具体需根据遮挡逻辑计算。
核心思路分析
这道题的难点在于子弹会被其他机器人阻挡,导致射程受限。直接模拟所有情况复杂度太高,我们需要利用排序和动态规划来优化。
关键性质
- 遮挡效应:子弹遇到最近的机器人就会停止。这意味着对于任意一堵墙,它只能被相邻的机器人摧毁。如果两个机器人之间没有墙,它们互不影响;如果有墙,则取决于谁先'够得着'。
- 相对顺序:由于机器人位置固定,我们可以按坐标从小到大排序处理。这样在处理当前机器人时,只需要考虑它与前一个机器人的关系。
- 坐标范围大:坐标可达 $10^9$,不能直接用数组存储状态,必须使用离散化或哈希映射。
动态规划状态设计
我们定义 dp[i][0] 表示处理到第 i 个机器人,且第 i 个机器人向左射击时的最大摧毁墙数。
定义 dp[i][1] 表示处理到第 i 个机器人,且第 i 个机器人向右射击时的最大摧毁墙数。
为了简化边界处理,可以在机器人列表首尾各添加一个虚拟机器人,位置分别在负无穷和正无穷,射程为 0。
状态转移
假设当前机器人为 i,前一个机器人为 i-1。
- 向左射击:
- 如果
i-1也向左,两者互不干扰,直接累加。 - 如果
i-1向右,两者可能产生重叠区域。需要计算重叠部分是否重复统计了墙的数量。若重叠,需减去重复部分。
- 如果
- 向右射击:
- 通常不会与前一个机器人的向左射击冲突(因为方向相反),主要受限于后一个机器人的位置。
内存优化与离散化
直接使用线段树维护区间最大值会导致内存超限(坐标范围太大)。解决方案是对所有关键坐标(机器人位置、墙壁位置、机器人射程边界)进行离散化。
离散化后,坐标范围缩小到 $O(N)$ 级别,此时可以使用线段树或树状数组来维护 dp[x] - g(x) 的最大值,其中 g(x) 是前缀墙数。这样可以将查询和更新操作优化到 $O( ext{log} N)$。
代码实现
以下是经过优化的 C++ 实现,包含离散化处理及动态规划逻辑。


