给你红点蓝点,找一个最大的圆,圆里没有蓝点并且至少有一个红点。边界可算可不算。
一开始没看懂题解,想了好久(一整天)才想明白是枚举弦上点二分半径check角度,看了下clj的代码发现思路都一样就开始写了。
借鉴了一下clj的代码。
调了一个多小时。
几个注意点:看到好多 random_shuffle 的,我没有,也感觉没什么必要。(另外cjl的代码去掉random_shuffle好像会WA。。。)
极角排序之后可能会遇到很多很多点全在一个角上,这个时候如果排序的话会麻烦,比方说我们要先减后加(哪里麻烦了啊???)
所以我每次check是不是扫完了完整的一段,也可以理解成我们扫角度不扫点。
小优化,每次二分先check ans,然后把l设成ans。
关于怎么求角的范围:两个圆夹起来就是了,初中解析几何?
千万不要把二分的eps设成1e-8,不然你会在test5tle到自闭并且还根本不知道哪里T了。
(感冒摸了三天鱼了。不过这题收获还蛮大的)
1 #include <bits/stdc++.h> 2 #define rep(x) for(int i=0;i<x;i++) 3 #define mk(a,b) make_pair(a,b) 4 using namespace std; 5 typedef double db; 6 const db eps=1e-6; 7 const db pi=acos(-1); 8 int sign(db k){ 9 if (k>eps) return 1; else if (k<-eps) return -1; return 0; 10 } 11 int cmp(db k1,db k2){return sign(k1-k2);} 12 struct point{ 13 db x,y; 14 point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};} 15 point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};} 16 point operator * (db k1) const{return (point){x*k1,y*k1};} 17 point operator / (db k1) const{return (point){x/k1,y/k1};} 18 int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;} 19 // 逆时针旋转 20 point turn(db k1){return (point){x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1)};} 21 bool operator < (const point k1) const{ 22 int a=cmp(x,k1.x); 23 if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1; 24 } 25 db abs(){return sqrt(x*x+y*y);} 26 db abs2(){return x*x+y*y;} 27 db dis(point k1){return ((*this)-k1).abs();} 28 db getw(){return atan2(y,x);} 29 int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)==-1);} 30 }; 31 db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;} 32 db dot(point k1,point k2){return k1.x*k2.x+k1.y*k2.y;} 33 db slove(db S){ 34 if(S<0)S+=2*pi; 35 else if(S>=2*pi) S-=2*pi; 36 return S; 37 } 38 point r[1005],b[1005]; 39 vector<point> p; 40 int n,m; 41 vector<pair<db,int>> g; 42 bool check(int id,db R){ 43 g.clear(); 44 point o = p[id]; 45 rep(n+m){ 46 if(i==id)continue; 47 point tmp = p[i]; 48 db d = tmp.dis(o); 49 if(cmp(d,R*2)>=0)continue; 50 db alf = acos(d/2/R); 51 db delta = atan2(tmp.y-o.y,tmp.x-o.x); 52 db l = slove(delta-alf),r=slove(delta+alf); 53 if(l<r){ 54 g.push_back(mk(l,i<n?2:1)); 55 g.push_back(mk(r,-(i<n?2:1))); 56 }else{ 57 g.push_back(mk(l,i<n?2:1)); 58 g.push_back(mk(2*pi,-(i<n?2:1))); 59 g.push_back(mk(0,i<n?2:1)); 60 g.push_back(mk(r,-(i<n?2:1))); 61 } 62 } 63 if(id<n)g.push_back(mk(0,id<n?2:1)),g.push_back(mk(2*pi,-(id<n?2:1))); 64 sort(g.begin(),g.end()); 65 int rn=0,bn=0; 66 rep(g.size()){ 67 if((i==g.size()-1||g[i].first!=g[i+1].first)&&rn>0&&bn<=0)return true; 68 if(abs(g[i].second)==1) 69 bn+=g[i].second; 70 else 71 rn+=g[i].second/2; 72 } 73 return false; 74 } 75 //枚举弦上点,二分半径,check角度范围,判断是否可行 76 int main(){ 77 //freopen("zibi.in","r",stdin); 78 scanf("%d%d",&n,&m); 79 rep(n) scanf("%lf%lf",&r[i].x,&r[i].y),p.push_back(r[i]); 80 rep(m) scanf("%lf%lf",&b[i].x,&b[i].y),p.push_back(b[i]); 81 bool f=0; 82 rep(n+m) 83 if(check(i,1e15)) 84 //return 0*printf("%d -1 ",i); 85 return 0*printf("-1 "); 86 db ans = 0; 87 //random_shuffle(p.begin(),p.begin()+n); 88 //random_shuffle(p.begin()+n,p.end()); 89 for(int i=0;i<n+m;i++){ 90 db l=ans,r=1e9; 91 if(check(i,ans)) { 92 while (l + eps < r) { 93 db mid = (l + r) / 2; 94 if (check(i, mid)) 95 l = mid; 96 else r = mid; 97 } 98 ans = l; 99 // printf("%d %.11f ",i,ans); 100 } 101 } 102 printf("%.11f ",ans); 103 } 104 /** 105 106 */ 107 /** 108 109 */