UVALive 5000 Underwater Snipers --二分
题意:一条河岸线y=k,y>k区域有n个敌人,现在要在y<=k区域布置S个狙击手,狙击手的狙击范围为距离自己半径为D的圆内,问满足能够狙死所有的敌人的情况下,离河岸线最近的那个狙击手的离河岸线的最大距离是多少。
解法:求最小值最大的问题。二分这个距离,如果距离为x,那么最好是狙击手都站到y=k-x处,可以最大范围地打到敌人。
然后check的时候求出每个敌人在y=k-x线上的能够打到他的狙击手范围,为[Xi-sqrt(D^2-(Yi-k+x)*(Yi-k+x),Xi+sqrt(D^2-(Yi-k+x)*(Yi-k+x)],
然后就变成了区间选点问题,将所有的范围按右端点排序,扫一遍判断这么多区间需要布置多少个狙击手,最后如果需要的>S,那么check失败,否则成功。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define ll long long using namespace std; #define N 10007 struct node { ll a,b; }p[N],seg[N]; int n,S; ll k,D; int cmp(node ka,node kb) { return ka.b < kb.b; } bool check(ll x) { for(int i=1;i<=n;i++) { if(p[i].b-k+x > D) return false; double t = (double)(p[i].b-k+x); double delta = sqrt((double)D*D-t*t); seg[i].a = p[i].a - (ll)delta; seg[i].b = p[i].a + (ll)delta; } sort(seg+1,seg+n+1,cmp); int cnt = 1; ll R = seg[1].b; for(int i=2;i<=n;i++) { if(seg[i].a > R) { cnt++; R = seg[i].b; } } if(cnt > S) return false; return true; } int main() { int t,cs = 1,i,j; scanf("%d",&t); while(t--) { scanf("%lld%d%d%lld",&k,&n,&S,&D); for(i=1;i<=n;i++) cin>>p[i].a>>p[i].b; ll low = 0, high = D; while(low <= high) { ll mid = (low+high)/2LL; if(check(mid)) low = mid+1; else high = mid-1; } printf("Case %d: ",cs++); if(high < 0) puts("IMPOSSIBLE"); else printf("%lld\n",high); } return 0; }
作者:whatbeg
出处1:http://whatbeg.com/
出处2:http://www.cnblogs.com/whatbeg/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
更多精彩文章抢先看?详见我的独立博客: whatbeg.com