路灯照明问题
难度:★★
区间合并,排序和扫描。
路灯照明问题
时间限制:1秒 | 内存限制:262144K | 语言限制:不限
题目描述:
在一条笔直的公路上安装了N个路灯,从位置0开始安装,路灯之间间距固定为100米。 每个路灯都有自己的照明半径,请计算第一个路灯和最后一个路灯之间,无法照明的区间的长度和。
输入描述:
第一行为一个数N,表示路灯个数,1<=N<=100000
第二行为N个空格分隔的数,表示路径的照明半径,1<=照明半径<=100000*100输出描述:
第一个路灯和最后一个路灯之间,无法照明的区间的长度和
示例1
输入
2
50 50
输出
0
说明
路灯1覆盖0-50,路灯2覆盖50-100,路灯1和路灯2之间(0米-100米)无未覆盖的区间
示例2
输入
4
50 70 20 70
输出
20
说明
[170,180],[220,230],两个未覆盖的区间,总里程为20
解题思路:
- 首先,我们需要接收输入,根据输入创建一个列表,每个元素是一个包含左边界和右边界的数组,代表每个路灯的照射范围。
- 其次,我们对列表进行排序,根据每个数组的左边界值进行排序。
- 在排序后,我们需要判断是否存在一盏路灯的照射范围覆盖了全部区域。如果存在,那么未覆盖区域就为0,直接输出结果。
- 如果不存在这样的路灯,我们就开始遍历这个排序后的列表。在遍历过程中,我们比较当前路灯的左边界和前一个路灯的右边界,如果当前路灯的左边界大于前一个路灯的右边界,就说明存在未被覆盖的区间,把这个区间的长度加入到总的未覆盖长度中。
- 最后,我们还需要检查最后一个路灯的右边界是否小于整个区域的右边界,如果小于,就把这个未被覆盖的区间长度也加入到总的未覆盖长度中。
JAVA代码:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt(); // 读取路灯的数量
List<int[]> list = new ArrayList<>(); // 创建列表来保存每个路灯的照射范围
for (int i = 0; i < n; i++) { // 对每个路灯进行处理
int temp = scan.nextInt(); // 读取路灯的照射半径
int k = i * 100; // 计算路灯的位置
int left = k - temp; // 计算照射范围的左边界
int right = k + temp; // 计算照射范围的右边界
if (left < 0) {
left = 0; // 确保左边界不小于0
}
if (right > 100 * (n - 1)) {
right = 100 * (n - 1); // 确保右边界不大于整个区域的右边界
}
list.add(new int[]{left, right}); // 把这个照射范围添加到列表中
}
// 根据左边界对列表进行排序
list.sort(Comparator.comparingInt(a -> a[0]));
// 检查是否存在一盏路灯的照射范围覆盖了全部区域
for (int[] interval : list) {
if (interval[0] <= 0 && interval[1] >= 100 * (n - 1)) {
System.out.println(0); // 如果存在这样的路灯,就输出0,并结束程序
return;
}
}
int total = 0; // 用来保存总的未覆盖长度
int end = 0; // 保存当前的照射范围右边界
// 遍历排序后的列表,寻找未覆盖的区间
for (int[] interval : list) {
if (interval[0] > end) { // 如果当前路灯的左边界大于前一个路灯的右边界,就找到了一个未覆盖的区间
total += interval[0] - end; // 把这个区间的长度加入到总的未覆盖长度中
}
end = Math.max(end, interval[1]); // 更新当前的照射范围右边界
}
// 检查最后一个路灯的右边界是否小于整个区域的右边界
if (end < 100 * (n - 1)) {
total += 100 * (n - 1) - end; // 如果小于,就把这个未被覆盖的区间长度加入到总的未覆盖长度中
}
System.out.println(total); // 输出总的未覆盖长度
}
}
代码说明:
- 首先,我们使用
Scanner
从输入中读取路灯的数量,然后创建一个数组来存储每个路灯的照射半径。 - 之后,我们对这个数组进行排序,以便于我们后续的操作。
- 创建一个变量
end
来保存当前的照射范围右边界,初始值为0。同时,创建一个变量total
来保存总的未覆盖长度,初始值也为0。 - 开始遍历每个路灯,对于每个路灯,我们计算它的左边界(即
i * 100 - lights[i]
),然后与end
比较。- 如果当前路灯的左边界大于
end
,那么在end
和当前路灯的左边界之间就存在一个未被覆盖的区间,我们把这个区间的长度加到total
上。 - 如果当前路灯的左边界小于等于
end
,那么这个路灯的照射范围是被覆盖的,我们不需要对total
进行操作。
- 如果当前路灯的左边界大于
- 在处理完当前路灯的左边界之后,我们需要更新
end
。end
应该是当前路灯的右边界(即i * 100 + lights[i]
)和当前end
中的较大值。这样可以确保end
总是最大的右边界,避免重复计算。 - 在处理完所有的路灯之后,我们还需要检查一下最后一个路灯的右边界是否小于整个区域的右边界(即
100 * (n - 1)
)。如果小于,那么在这两个边界之间就存在一个未被覆盖的区间,我们把这个区间的长度加到total
上。 - 最后,我们输出
total
,即总的未覆盖长度。
这个解决方案利用了排序和扫描的方法,将复杂度控制在了O(n log n),其中n是路灯的数量。