目录
问题
假设海岸是一条无限直线。陆地在海岸的一侧,大海在另一侧。每个小岛都是位于海边的一个点。而任何位于海岸的雷达装置只能覆盖d距离,因此,如果它们之间的距离最多为d,则海中的岛屿可以被半径装置覆盖。
我们使用笛卡尔坐标系,定义海岸是x轴。海面在x轴上方,陆地一侧在x轴以上。给定海中每个岛屿的位置,并给定雷达安装的覆盖范围的距离,您的任务是编写一个程序来查找覆盖所有岛屿的最小数量的雷达安装。请注意,岛屿的位置由其 x-y 坐标表示。
输入格式:
输入由多个测试用例组成。每种情况的第一行包含两个整数 n (1<=n<=1000) 和 d,其中 n 是海中岛屿的数量,d 是雷达装置的覆盖距离。后跟 n 行,每行包含两个整数,表示每个岛位置的坐标。然后跟着一个空行来分隔样例。
输入由一条包含零对的数据终止。
输出格式:
对于每个测试用例输出一行,包括测试用例编号,后跟所需的最小雷达安装数量。“-1”安装意味着没有针对这种情况的解决方案。
输入样例:
在这里给出一组输入。例如:
3 2
1 2
-3 1
2 1
1 2
0 2
0 0
输出样例:
在这里给出相应的输出。例如:
Case 1: 2
Case 2: 1
因为我之前看网上的解析,感觉我看的那几个都太懒了,都去复制几个图片和三句话,解析不够清楚,搞得我看了半天,所以我写下这个,我尽量搞清楚点。
思路
因为题目说是海岸线,并且雷达只能在海岸线上,所以我们可以把海岸线当作一个xy轴的x轴,然后因为题目也提到雷达范围为d,并且当出现雷达不可能覆盖的小岛的时候就输出-1,那么我们就可以知道当一个小岛的y>d时,那么雷达必不可能覆盖得到,因为雷达的y是没法变的,都是在海岸线上。画的不好,大概是这个意思,下么那个是直角。
然后要是y都小于d,就说明剩下的小岛都一定能够覆盖到,所以我们就应该开始想因该如何解决这个问题,这个题可以用贪心,原因你把后面看完了就知道了(但是老实说,我最开始并没有想到用他们的交集,至于什么是交集,也是后面的)。
我们可以在岛上假设一个雷达站,然后绕着它画一个圈,然后圈和x的交汇的范围就是我们需要建设雷达站的位置范围。
然后我们可以把每一个小岛都这样搞一个圈,然后将全部小岛都按照小岛左边的值排一个顺序(这是后面做题才需要干的),把这些小岛全部一起看我们能发现一些重叠的地方,而这些地方就是可以放雷达的地方。
现在我们就该考虑一下如何安装雷达站。我们可以从黑色小岛的开始,将将他的左边界设置为left,右边界设置为right,然后因为我们一开始将小岛依照left的值排过序,所以下一个小岛比如红色小岛的left一定是比黑色的靠右,然后我们只需要判断红色小岛的left是否超过黑色小岛的right,要是没有超过,就可以共用一个雷达站,后面黄色小岛的left超过了,所以需要一个新的雷达。
注意
我们对于小岛的right要更新,因为又可能会有下面的情况。
就是我们将红色小岛视为可以和黑色小岛公用一个雷达站,但是此时用的right仍然是黑色的,可是红色的right比黑色的小,如果不改的话下一个黄色的小岛也满足条件了,但是显然我们现在需要两个雷达。
代码
#include <iostream>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<algorithm>
#include<map>
#include <stdio.h>
#include <unordered_map>
#include <math.h>
#include <numeric>
using namespace std;
//我定义了一个结构体,用来装一个小岛的left和right
typedef struct asdf{
double left;
double right;
}dian;
dian point[1009];
//后面排序遵照的规则
bool cmd1(dian a,dian b)
{
return a.left<b.left;
}
int main(){
int n,d;
//因为有多组数据,所以先记着这是第几组
int num=1;
while(cin>>n>>d)
{
//结束证明
if(n==0&&d==0)
{
break;
}
//先用来记录有没有小岛的y>d
int jieguo=1;
//开始输入小岛的x和y
for(int i=0;i<n;i++)
{
int a,b;
cin>>a>>b;
//当有小岛的y>d,那么记下来,其实这应该就可以直接退出了
if(b>d)
{
jieguo=-1;
}
//因为我们需要计算一个小岛的left和right,所以需要用勾股定理
double fanwei=sqrt(d*d-b*b);
//小岛的left
point[i].left=a-fanwei;
//小岛的right
point[i].right=a+fanwei;
}
//当这个为-1的时候就表示有小岛的y>d了,所以就不进行后面的了
if(jieguo!=-1)
{
//将小岛按照小岛的left来从小到大排序
sort(point,point+n,cmd1);
//youbian是拼音,用来记录右边界,最开始是point[0]
double youbianju=point[0].right;
for(int i=0;i<n;i++)
{
//当当前小岛的left>右边界时,就表示我们需要用一个新的雷达
if(point[i].left>youbianju)
{
//此时表示雷达的个数
jieguo++;
//我们更行右边界
youbianju=point[i].right;
}
//我们判断当前小岛的right有没有右边界小,如果小的话就更新右边界
else if(point[i].right<youbianju)
{
youbianju=point[i].right;
}
}
}
cout<<"Case "<<num<<": "<<jieguo<<endl;
num++;
}
return 0;
}