题目大意:n个洒水器水平安装在一个 l*w 的草坪上(长为l米,宽为w米),已知每个洒水器的水平位子和洒水的直径,求最少需要多少个洒水器同时开才能够覆盖整个草坪?如下图
解题思路
贪心法:对于每个洒水器(也就是每个园)来说,与草坪都会有四个交点(当w/2大于半径时没有交点,等于时只有两个交点),构成两个玄(左边和右边,玄的长为w,位子分别记为ll和rr)两条玄之间的线段为(ll,rr),如果想要覆盖整个草坪的话,就是从n个(ll,rr)线段,能够覆盖线段(0,l),看能否覆盖的话,大致思路就是采用贪心法,按照线段的左端ll对n条线段进行排序,然后固定 rr(rr从0开始),从左到右扫描线段,每次取能使得rr达到最大的线段,更新rr。直到rr>=l
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAX = 10000;
struct node{
double left;
double right;
}circles[MAX];
int cmp(const void *a,const void *b){
return ((node *)a)->left - ((node *)b)->left;
}
int main(){
int n;
double l,w;
int pos;
double radius;
while(cin>>n>>l>>w){
for(int i=0; i<n; ++i){
cin>>pos>>radius;
if(w/2 >= radius){
circles[i].left=pos;
circles[i].right=pos;
}else{
double tmp=sqrt(radius*radius - w*w/4);
circles[i].left=pos-tmp;
circles[i].right=pos+tmp;
}
}
qsort(circles,n,sizeof(node),cmp);
int cnt=0,i=0;
double RR=0,LL=0;
bool flag=true;
while(true){
while(circles[i].left <= LL){
if(circles[i].right > RR){
RR = circles[i].right;
}
++i;
if(i==n)
break;
}
cnt++;
if(RR >= l){
break;
}
if(RR <= LL || i == n){
flag=false;
break;
}
LL = RR;
}
if(flag){
cout<<cnt<<endl;
}else {
cout<<-1<<endl;
}
}
return 0;
}