一开始以为是一道简单的区间覆盖贪心,区间是离散化的。后来才发现区间是连续的,每个sprinkler覆盖的区间为[p-sqrt(r*r-w*w/4),p+sqrt(r*r+w*w/4)]。
贪心策略在lrj的入门经典里有非常详细的叙述。这里简单说一下,就是已经覆盖的区间全部排除不考虑,然后在剩下的区间中选择能覆盖的最远的那个即可。这里我用的是优先队列的方式实现的。
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
const double eps=1e-10;
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
int n,l,w;
struct interval
{
double l,r;
interval(double l=0,double r=0):l(l),r(r){}
bool operator<(const interval& t) const
{
return dcmp(l-t.l)>0||(dcmp(l-t.l)==0&&dcmp(r-t.r)<0);
}
};
priority_queue<interval> q;
int main()
{
freopen("in.txt","r",stdin);
while(cin>>n>>l>>w)
{
while(!q.empty()) q.pop();
int p,r;
for(int i=0;i<n;i++)
{
cin>>p>>r;
if(w>2*r) continue;
double t=sqrt(1.0*r*r-1.0*w*w/4);
q.push(interval(p-t,p+t));
}
double cover=0;
int ans=0;
while(!q.empty())
{
if(dcmp(cover-l)>=0) break;
double L=q.top().l,R=q.top().r;
q.pop();
if(dcmp(R-cover)<=0) continue;
else if(dcmp(L-cover)<0) q.push(interval(cover,R));
else if(dcmp(L>cover)>0) break;
else
{
ans++;
cover=R;
}
}
if(dcmp(cover-l)>=0) cout<<ans<<endl;
else cout<<-1<<endl;
}
return 0;
}