解题思路
如图,对于任意一个建筑物
(
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);
}