思路
看到圆就很想吐,但幸好想到了每个圆代表的区间其实就是
所以问题就转化为:最少能用多少个子区间将总区间表示出来。
然后是怎么选区间的问题,只要将每个区间排序,然后贪心地去选就好了。
先排序,每个区间L小在前,然后是R大在前,然后只要我没有达到最大长度,
就选一个区间使得我能到达最远的距离,然后ans++,如果选完n个都无法达到那个长度,
就输出-1,否则输出ans。
做法是O(n^2)的,应该有更优的,但这个数据范围够用了。
代码
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int maxn=15005; struct C{ double l,r; }s[maxn]; int t,n,cnt; double L,w,x,r; bool cmp(C a,C b){ if(a.l==b.l) return a.r>b.r; return a.l<b.l; } signed main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>t; while(t--){ cnt=0; cin>>n>>L>>w; for(int i=1;i<=n;i++){ cin>>x>>r; if(r*2<=w) continue; s[++cnt].l=x-sqrt(r*r-w*w/4); s[cnt].r=x+sqrt(r*r-w*w/4); } sort(s+1,s+1+cnt,cmp); // for(int i=1;i<=cnt;i++) cout<<s[i].l<<" "<<s[i].r<<endl; double idx=0,mx=0; int ans=0; for(int i=1;i<=cnt;i++){ //最多是打开cnt个喷头 for(int j=1;j<=cnt;j++){ if(s[j].r>idx&&s[j].l<=idx){ //达到要求更进一步 if(mx<s[j].r) mx=s[j].r; //取能够到的最远距离 } } ans++; //打开了一个喷头 idx=mx; // cout<<idx<<" "<<ans<<" "<<L<<endl; if(idx>=L) break; //达到目的 } if(idx>=L) cout<<ans<<"\n"; else cout<<-1<<"\n"; } return 0; }