解题思路
如图,对于任意一个建筑物 ( x , y ) (x,y) (x,y),我们在x轴上计算出能够侦察到该建筑物的雷达建造区间[l,r]。
有勾股定理得: l = x − 根 号 ( d 2 − y 2 ) l=x-根号(d^2-y^2) l=x−根号(d2−y2), r = x + 根 号 ( d 2 − y 2 ) r=x+根号(d^2-y^2) r=x+根号(d2−y2)
当 d 2 − y 2 < 0 d^2-y^2<0 d2−y2<0即 d < y d<y d<y时,该建筑物不可能被雷达监测到,可以直接输出 − 1 -1 −1.
我们可以将所有建筑物都转换为雷达建造区间,问题转换为:给定 n n n个区间,在数轴上方尽量少的点,使得每个区间都包含一个点。
贪心策略:
- 将所有区间按右端点从小到大排序。
- 一次考虑每个区间
- 若当前区间内包含最后一个选择的点,直接跳过
- 若当前区间内不包含最后一个选择的点,则在该区间的右端点放一个新的点。
PS:我们很容易做错这题,比如我这个蒟蒻 直接排序,然后如果当前点的左端点比当前区间的左端点大 2 ∗ d 2*d 2∗d,就 a n s + + ans++ ans++。这是不对的,因为雷达的区间是一个圆,这样做是把雷达的区间当做了一个 d ∗ d d*d d∗d的矩阵。
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
long long t,n,d,ans,x,y;
double w;
bool flag;
struct c{
double x,y;
}a[3000];
bool cmp(const c&a,const c&b)
{
return a.y<b.y;
}
int main() {
scanf("%lld%lld",&n,&d);
for(int i=1; i<=n; i++) {
scanf("%lld%lld",&y,&x);
if(abs(x)>d)
flag=1;
a[i].x=y-sqrt(d*d-x*x);
a[i].y=y+sqrt(d*d-x*x);
}
if(flag==1)
{
printf("-1");
return 0;
}
sort(a+1,a+n+1,cmp);
ans=1,w=a[1].y;
for(int i=2; i<=n; i++) {
if(a[i].x<=w&&a[i].y>=w)
continue;
else
{
ans++;
w=a[i].y;
}
}
printf("%lld",ans);
}