雷达安装
题目传送门:https://www.luogu.com.cn/problem/P1325
题目描述
假设海岸线是一条无限延伸的直线。它的一侧是陆地,另一侧是海洋。每一座小岛是在海面上的一个点。雷达必须安装在陆地上(包括海岸线),并且每个雷达都有相同的扫描范围 d d d。你的任务是建立尽量少的雷达站,使所有小岛都在扫描范围之内。
数据使用笛卡尔坐标系,定义海岸线为 x x x 轴。在 x x x 轴上方为海洋,下方为陆地。
输入格式
第一行包括 2 2 2 个整数 n n n 和 d d d, n n n 是岛屿数目, d d d 是雷达扫描范围。
接下来 n n n 行,每行两个整数,为岛屿坐标。
输出格式
一个整数表示最少需要的雷达数目,若不可能覆盖所有岛屿,输出 -1
。
样例 #1
样例输入 #1
3 2
1 2
-3 1
2 1
样例输出 #1
2
提示
样例 1 解释
数据范围
对于全部数据, n ≤ 1000 n\le1000 n≤1000, d ≤ 2 × 1 0 4 d \le 2\times 10^4 d≤2×104, ∣ x i ∣ ≤ 2 × 1 0 6 | x_i | \le 2 \times 10^6 ∣xi∣≤2×106, 0 ≤ y i ≤ 2 × 1 0 4 0 \le y_i \le 2\times 10^4 0≤yi≤2×104。
解读题目大意
海上有岛,求在陆地上最少装多少扫射半径为d的雷达,陆地包括海岸线,由此可知雷达全部建在海岸线(X轴)上是最优的,覆盖范围是最广的。
解题思路
求出每个岛在x轴上最大(最小)能覆盖到的雷达建设点(包括左端点和有端点,用勾股定理计算),每个岛会计算的到一个区间,表示在该区间范围内若有雷达,则可以覆盖到这个岛。由此转换为区间选点思想解题,计算原理图示如下:
然后对右区间排序,贪心思想求取最少雷达数:对求得的区间按右端点升序排序,首先定义第一个岛P1
是有雷达覆盖的,若P2
岛的左区间小于等于P1
右区间,则表示也能被这个雷达覆盖,不用再加雷达;反之,如P3
的左区间大于P1
的右区间,覆盖不到,需要在P3
范围内加一个雷达,下一个岛的左端点则需要与P3
的右端点比较,以此类推,直到遍历完所有的区间,即可得到最少需要多少雷达。
示意图如下:下图共需要到3个雷达。
注意: 考虑不满足条件的情况,即若岛 的y
坐标大于雷达半径d
,则雷达必然覆盖不到。
代码实现
import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
public class P1325_雷达安装 {
public static void main(String[] args) throws IOException {
BufferedReader bu = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(bu);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
in.nextToken();
int n = (int)in.nval;
in.nextToken();
int d = (int)in.nval;
int [][] a = new int[n][2];
for (int i = 0; i <n ; i++) {
in.nextToken();
a[i][0] = (int)in.nval;
in.nextToken();
a[i][1] = (int)in.nval;
if(a[n-1][1]>d){
out.print(-1);
out.flush();
return;
}
}
double [][] b = new double[n][2];//存储区间
for (int i = 0; i < n ; i++) {
double x = Math.sqrt(d*d-a[i][1]*a[i][1]);
b[i][0] = a[i][0]-x;
b[i][1] = a[i][0]+x;
}
int res = 1;//雷达个数
//将区间按右端点排序
Arrays.sort(b, new Comparator<double[]>() {
@Override
public int compare(double[] o1, double[] o2) {
if (o1[1] < o2[1]) {
return -1;
} else if (o1[1] > o2[1]) {
return 1;
} else {
return 0;
}
}
});
//贪心选点:比较若j的左端点大于i的右端点,则超出覆盖不到,添加一个雷达
int i = 0;int j = 1;
while(j<n) {
if(b[j][0]>b[i][1]){
res++;
i = j;
}
j++;
}
out.print(res);
out.flush();
}
}
如果本文对你有帮助,可以点个赞再走噢!