1. 程式人生 > >bzoj2823: [AHOI2012]信號塔&&1336: [Balkan2002]Alien最小圓覆蓋&&1337: 最小圓覆蓋

bzoj2823: [AHOI2012]信號塔&&1336: [Balkan2002]Alien最小圓覆蓋&&1337: 最小圓覆蓋

clu name int() multi simple truct 隨機化 隨機 eps

首先我寫了個凸包就溜了

這是最小圓覆蓋問題,今晚學了一下

先隨機化點,一個個加入

假設當前圓心為o,半徑為r,加入的點為i

若i不在圓裏面,令圓心為i,半徑為0

再重新從1~i-1不停找j不在圓裏面,令圓心為ij中點,直徑為ij距離

再重新在1~j-1不停找k不在圓裏面,三點可確定一圓,初中數學

復雜度看似O(n^3)實則O(n),好玄學

坑點:註意如果用點斜式表示方程有斜率為不存在的情況,需要特判

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include
<algorithm> #include<cmath> using namespace std; const double eps=1e-8; double sqr(double x){return x*x;} struct point{ double x,y;point(){} point(double X,double Y){x=X,y=Y;} }; double getdis(point p1,point p2){return sqrt(sqr(p1.x-p2.x)+sqr(p1.y-p2.y));} point middle(point p1,point p2){
return point((p1.x+p2.x)/2,(p1.y+p2.y)/2);} double slope (point p1,point p2) { if(p2.x==p1.x)return 0; return (p2.y-p1.y)/(p2.x-p1.x); } double multi(point p1,point p2,point p0) { double x1,y1,x2,y2; x1=p1.x-p0.x; y1=p1.y-p0.y; x2=p2.x-p0.x; y2=p2.y-p0.y; return x1*y2-x2*y1; }
struct segment{ double k,b;segment(){} segment(double K,double B){k=K,b=B;} }; segment getseg(double k,point pp){return segment(k,pp.y-k*pp.x);} point intersection(segment s1,segment s2) { double x=(s2.b-s1.b)/(s1.k-s2.k); double y=s1.k*x+s1.b; return point(x,y); } //--------------------------------------simple-------------------------------------------------------- int n; point p[1100000]; bool cmp(point p1,point p2) { double d=multi(p1,p2,p[1]); if(fabs(d)<=eps)return getdis(p1,p[1])<getdis(p2,p[1]); else return d>0; } int top,sta[1100000]; void graham() { sort(p+2,p+n+1,cmp); top=0;sta[++top]=1,sta[++top]=2; double g; for(int i=3;i<=n;i++) { while(top>=2) { g=multi(p[sta[top]],p[i],p[sta[top-1]]); if(g<0||fabs(g)<=eps)top--; else break; } sta[++top]=i; } } //------------------------------------graham---------------------------------------------------------- point getcore(point p1,point p2,point p3) { double g=multi(p1,p2,p3); if(fabs(g)<=eps) { double d1=getdis(p1,p2),d2=getdis(p1,p3),d3=getdis(p2,p3); if(d1>d2&&d1>d3)return middle(p1,p2); if(d2>d1&&d2>d3)return middle(p1,p3); if(d3>d1&&d3>d2)return middle(p2,p3); } else { segment s1,s2; if(slope(p1,p2)==0) { s1=getseg(-1/slope(p1,p3),middle(p1,p3)); s2=getseg(-1/slope(p2,p3),middle(p2,p3)); } else if(slope(p1,p3)==0) { s1=getseg(-1/slope(p1,p2),middle(p1,p2)); s2=getseg(-1/slope(p2,p3),middle(p2,p3)); } else { s1=getseg(-1/slope(p1,p2),middle(p1,p2)); s2=getseg(-1/slope(p1,p3),middle(p1,p3)); } return intersection(s1,s2); } } void circlecover() { random_shuffle(sta+1,sta+top+1); point o=p[sta[1]];double r=0,d; for(int i=2;i<=top;i++) if(getdis(o,p[sta[i]])>r) { o=p[sta[i]],r=0; for(int j=1;j<i;j++) if(getdis(o,p[sta[j]])>r) { o=middle(p[sta[i]],p[sta[j]]),r=getdis(o,p[sta[i]]); for(int k=1;k<j;k++) if(getdis(o,p[sta[k]])>r) o=getcore(p[sta[i]],p[sta[j]],p[sta[k]]),r=getdis(o,p[sta[i]]); } } printf("%.2lf %.2lf %.2lf\n",o.x,o.y,r); } //------------------------------------solve---------------------------------------------------------- int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); if(p[i].y<p[1].y||(p[i].y==p[1].y&&p[i].x<p[1].x)) swap(p[i],p[1]); } graham(); circlecover(); return 0; }

bzoj2823: [AHOI2012]信號塔&&1336: [Balkan2002]Alien最小圓覆蓋&&1337: 最小圓覆蓋