题目
题解
这里有一个十分重要的思路(其实贪心都不是特别重要),就是如何处理小岛和雷达的关系,我们观察好像很难搞,但是其实我们是能对于每一个小岛,在地平线求出一个区间,表示在这个区间放雷达能够覆盖这个小岛。
即:
至于区间(l)和(r),用勾股定理不难求出。
然后就是问选最少的点覆盖这些区间了。(这里的覆盖指的是这个雷达在这个区间中,即为覆盖了这个区间,而下面大部分的区间覆盖就只是单纯的指有交集)
现在需要明白,选的点数至少是(最多是)最多的不相互重合的区间的个数,如:([1,4],[2,5],[5,7])中([1,4])和([5,7])就是没有交集的两个区间,所以就是两个点。
至少我就不证明了,这里给出“最多是”的伪证明:
这里采用构造的方法构造出一种最少方案等于最多的不相互重合的区间的个数即可证明。
加入(X)区间完全被(Y)区间覆盖,那么和(Y)无交集的集合也和(X)无交集,因此我们可以把(Y)删掉,因为如果(X)被选中的点覆盖了,(Y)也是,所以(Y)可以完全被(X)所代替(如果你还不知道为什么看后面就可以了)。然后我们挑选出了(k)个没有交集的区间,保证(k)最大的情况下。
有些区间一定会被选中,也就是他是孤零零一个人,没有区间和它有交集,但是对于有交集的情况,由于我们去掉了完全覆盖的情况,只剩下了部分覆盖,即(r-l)覆盖。
那么我们可以在这(k)个区间的(l)或者(r)下个雷达(注意,要么一起(l),要么一起(r)),如果下(l)或者下(r)都不能覆盖所有的区间,则一定(一定存在我不会严谨证明,但是结合(r-l)覆盖想想都知道应该是一定吧QAQ)存在这种情况(蓝色是(k)个区间中的区间):
这个时候如果我们选下面的黑色,无交集区间就多了一个,不符合(k)最大的理论,矛盾。
因此一定可以构造出一种情况使得雷达数等于(k)。
证毕。(其实“至少是”也是因为无交集的区间必须每个装一个雷达所以才是“至少是”)
所以至少和最多合在一起就是等于啦。
那么如何证明我们自己的构造方法是对的呢?假设我们的雷达选择一个它所覆盖的区间作为它的认定区间,那么我们只需要证明一定存在一种认定方案使得认定区间不重复即可。
下面两种时间复杂度都是(O(nlogn))。
做法1
我的做法是把所有区间按(l)排序,记录一个(R),对于目前的区间,如果(l[i]≤R),则说明这个区间和前面的区间存在交集,那么(R=min(R,r[i])),同时把这个区间扔进队列中,如果(l[i]>R),那么说明出现了无交集的两个区间,(ans++),然后把雷达放在(R),这个雷达认定区间为(r[k]=R)((k)号区间是在队列中的),清空队列,同时(R=r[i]),将(i)扔进队列中,不难发现认定区间是无交集的。(注,其实对于放雷达的位置,只要是([l_max,r_min])这个区间中放都可以,由于(l)递增,其实就是在([l[i-1],R])这个区间放雷达都可以)
实际实现由于不用求认定区间,所以用不到队列。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1100
using namespace std;
struct node
{
double l,r;
}a[N];
int n,m;
inline bool cmp(node x,node y){return x.l<y.l;}
inline double mymin(double x,double y){return x<y?x:y;}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x,y;scanf("%d%d",&x,&y);
if(y>m)
{
printf("-1
");
return 0;
}
double f=sqrt(m*m-y*y);
a[i].l=x-f,a[i].r=x+f;
}
sort(a+1,a+n+1,cmp);
double R=999999999;
int ans=0;
for(int i=1;i<=n;i++)
{
if(a[i].l<=R)R=mymin(R,a[i].r);
else
{
ans++;
R=a[i].r;
}
}
printf("%d
",ans+1);
return 0;
}
做法2
https://www.acwing.com/solution/content/1061/
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef pair<double, double> PDD;
const int N = 1010;
const double eps = 1e-6, INF = 1e10;
int n, d;
PDD seg[N];
int main()
{
cin >> n >> d;
bool success = true;
for (int i = 0; i < n; i ++ )
{
int x, y;
cin >> x >> y;
if (y > d)
{
success = false;
break;
}
auto len = sqrt(d * d - y * y);
seg[i] = {x + len, x - len};
}
if (!success) puts("-1");
else
{
sort(seg, seg + n);
int res = 0;
double last = -INF;
for (int i = 0; i < n; i ++ )
{
if (seg[i].second > last + eps)
{
res ++ ;
last = seg[i].first;
}
}
cout << res << endl;
}
return 0;
}
作者:yxc
链接:https://www.acwing.com/solution/content/1061/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。