上接:贪心算法
1424:【例题3】喷水装置
题解
所以就可以吧这些圆简化为线段
思路
①读入,圆变线段
读入数据,并计算 a[cnt].s =p -sqrt((r*r)-(w/2.0)*(w/2.0));
a[cnt].e =p +sqrt((r*r)-(w/2.0)*(w/2.0));
②跑区间覆盖
按S[i].s进行从小到大快排,从左到右依次处理每个区间,跑区间覆盖
将所有的区间按左端点从小到大排序,依次处理每个区间。每次选择覆盖点s的区间中右端点坐标最大的一个,并将s更新为该区间的右端点坐标,直到选择的区间已包含了t为止
③输出
代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> using namespace std; int T; int n,l,w,r,p,cnt; struct app { double s,e; }a[20015]; bool cmp(app x,app y) { return x.s <y.s ; } void read() { cnt=0; scanf("%d%d%d",&n,&l,&w); for(int i=1;i<=n;i++) { scanf("%d%d",&p ,&r ); if(r<=w/2) continue; //直径无法完成w,没有用,直接不计入读入 cnt++; a[cnt].s =p -sqrt((r*r)-(w*w/4.0)); a[cnt].e =p +sqrt((r*r)-(w*w/4.0)); } } void solve() { int ans=0; int i=1; bool flag=1; double t=0; while(t<l) { ans++; double s=t; for(;a[i].s <=s&&i<=cnt ; i++) //依次找能够覆盖L点的最大右端点 if(t<a[i].e ) t=a[i].e ; if(t==s&&s<l) //中间有断层,且未到达终点,判断无解 { flag=0; printf("-1 "); break; } } if(flag) printf("%d ",ans); } int main() { scanf("%d",&T); while(T--) { read(); sort(a+1,a+cnt+1,cmp); solve(); } return 0; }