洛谷P1325 雷达安装【区间选点、贪心、排序】Java题解

讨论了如何在海岸线上布置雷达以覆盖所有岛屿,涉及贪心策略和坐标计算。
摘要由CSDN通过智能技术生成

雷达安装

题目传送门: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 n1000 d ≤ 2 × 1 0 4 d \le 2\times 10^4 d2×104 ∣ x i ∣ ≤ 2 × 1 0 6 | x_i | \le 2 \times 10^6 xi2×106 0 ≤ y i ≤ 2 × 1 0 4 0 \le y_i \le 2\times 10^4 0yi2×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();
    }
}

如果本文对你有帮助,可以点个赞再走噢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值