问题链接:Problem J
问题简述:
有一块草坪长为l,宽为w,同时有n个喷头,给出喷头的位置(距离草坪左端的距离),与喷头喷洒的范围,问喷头的范围能否覆盖整块草坪,若能,输出要开的最少喷头数,若不能,输出-1。
问题分析:
典型的区间覆盖问题。但该问题为二维问题,难度在于如何将二维问题转化为一维问题,从而用简单的一维区间覆盖解决问题。可以发现,喷头可以覆盖到的草坪上下两端的范围可以用勾股定理转换成水平方向的区间,而若能覆盖及上下两端,则水平方向必然也能覆盖到,因此只用将每个喷头可以覆盖到的最远上下两端点转换为覆盖区间,即可求解。求解区间覆盖问题用贪心思想即可,即每次取区间长度最长的区间。
程序说明:
要注意的一个细节是问题设计到的变量尽量都用double表示,防止勾股计算过程中忘记将整型转换为double而导致计算出现错误。
AC通过的C语言程序如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
#include<cmath>
using namespace std;
struct node{
int pos;
double l,r;
}point[10005];
bool cmp(node a,node b){
return a.l<b.l;
}
int main(){
std::ios::sync_with_stdio(false);
int n,l,w;
while(cin>>n>>l>>w){
double r;
double m=(double)w/2;
for(int i=0;i<n;i++){
cin>>point[i].pos>>r;
double del=sqrt(r*r-m*m);
point[i].l=point[i].pos-del;
point[i].r=point[i].pos+del;
}
sort(point,point+n,cmp);
if(point[0].l>0){
cout<<-1<<endl;
continue;
}
double L=0,R=0;
int ans=0;
while(R<l){
for(int i=0;i<n;i++){
if(point[i].l<=L&&point[i].r>R){
R=point[i].r;
}
}
if(R==L){
ans=-1;
break;
}
L=R;
ans++;
}
cout<<ans<<endl;
}
}