给出一堆点,求一个面积(半径)最小的圆,使得所有点都在它的内部或边界上.
随机增量法是这样的....
先随机打乱点的顺序......
然后,我们假设已经得到了点 $1,2,...,i$ 的最小覆盖圆,我们要求出点 $1,2,...,i,i+1$ 的最小覆盖圆.
怎么做? 考虑点 $i+1$ ,分两种情况:
1.如果点 $i+1$ 在点 $1,2,...,i$ 的最小覆盖圆里面或边界上,那么点 $1,2,...,i,i+1$ 的最小覆盖圆就是点 $1,2,...,i$ 的最小覆盖圆.
证明:
假设点 $1,2,...,i,i+1$ 的最小覆盖圆比点 $1,2,...,i$ 的最小覆盖圆小. 这意味着,我们可以用点 $1,2,...,i,i+1$ 的最小覆盖圆来覆盖点 $1,2,...,i$ ,因此我们找到了一个新的圆,它覆盖了点 $1,2,..,i$ 比 $1,2,...,i$ 的最小覆盖圆还要小.显然矛盾.
结合最小覆盖圆的唯一性可得出结论.
上述证明说明了,最小覆盖圆在我们依次添加点的过程中,面积(半径)一定单调不减的.
2.如果点 $i+1$ 在点 $1,2,...,i$ 的最小覆盖圆外,那么点 $i+1$ 一定在点 $1,2,...,i,i+1$ 的最小覆盖圆的边界上.
不会证!哪位神犇前来拯救我QAQ
有了这个性质以后,我们就可以按顺序来做"三点确定一个圆"的事情=.=
现在我们知道了点 $i+1$ 必定会在边界上. 那么我们再用一次这个方法:
假设我们已经得到了点 $1,2,...,j$ 的过点 $i+1$ 的最小覆盖圆. 现在我们要求点 $1,2,...,j,j+1$ 的,过点 $i+1$ 的最小覆盖圆. 如果点 $j+1$ 已经在那个最小覆盖圆里面,根据情况1可以将这个点忽略.如果不在,再用一次这个方法:
假设我们已经得到了点 $1,2,...,k$ 的,过两个点 $j+1,i+1$ 的最小覆盖圆. 现在我们要求点 $1,2,...,k,k+1$ 的,过点 $j+1,i+1$ 的最小覆盖圆. 如果点 $k+1$ 已经在那个最小覆盖圆里面,根据情况1可以将这个点忽略.如果不在,直接求三个点 $k+1,j+1,i+1$ 对应的外接三角形就是答案.
最后那句话不怎么理解QAQ......
另外怎么证明,最小覆盖圆只能有一个?
AC BZOJ 2823 裸的最小覆盖圆
1 #include <cstdio> 2 #include <fstream> 3 #include <iostream> 4 5 #include <cstdlib> 6 #include <cstring> 7 #include <algorithm> 8 #include <cmath> 9 10 #include <queue> 11 #include <vector> 12 #include <map> 13 #include <set> 14 #include <stack> 15 #include <list> 16 17 typedef unsigned int uint; 18 typedef long long int ll; 19 typedef unsigned long long int ull; 20 typedef double db; 21 typedef long double ldb; 22 23 using namespace std; 24 25 inline int getint() 26 { 27 int res=0; 28 char c=getchar(); 29 bool mi=false; 30 while(c<‘0‘ || c>‘9‘) mi=(c==‘-‘),c=getchar(); 31 while(‘0‘<=c && c<=‘9‘) res=res*10+c-‘0‘,c=getchar(); 32 return mi ? -res : res; 33 } 34 inline ll getll() 35 { 36 ll res=0; 37 char c=getchar(); 38 bool mi=false; 39 while(c<‘0‘ || c>‘9‘) mi=(c==‘-‘),c=getchar(); 40 while(‘0‘<=c && c<=‘9‘) res=res*10+c-‘0‘,c=getchar(); 41 return mi ? -res : res; 42 } 43 44 //============================================================================== 45 //============================================================================== 46 //============================================================================== 47 //============================================================================== 48 49 db eps=1e-6; 50 51 struct point 52 { 53 db x,y; 54 point(db x=0,db y=0):x(x),y(y){} 55 point operator+(point f) { return point(x+f.x,y+f.y); } 56 point operator*(db f) { return point(x*f,y*f); } 57 point operator*(point f) { return x*f.y-y*f.x; } 58 point operator-(point f) { return point(x-f.x,y-f.y); } 59 point operator()(point f) { return point(f.x-x,f.y-y); } 60 point&operator=(point f) { memcpy(this,&f,sizeof(point)); return *this; } 61 }; 62 63 db dist(const point &a,const point &b) 64 { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } 65 66 point cc(point&a,point&b,point&c) 67 { 68 point ret; 69 db a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)*0.5; 70 db a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)*0.5; 71 db d=a1*b2-a2*b1; 72 if(abs(d)<1e-12) return (b+c)*0.5; 73 ret.x=a.x+(c1*b2-c2*b1)/d; 74 ret.y=a.y+(a1*c2-a2*c1)/d; 75 return ret; 76 } 77 78 int n; 79 point a[1005000]; 80 81 void putres(db a,db b,db r) 82 {printf("%.2f %.2f %.2f\n",a,b,r);} 83 84 int main() 85 { 86 srand(23333); 87 88 n=getint(); 89 for(int i=0;i<n;i++) 90 scanf("%lf%lf",&a[i].x,&a[i].y); 91 92 if(n==0) { putres(0,0,0); return 0; } 93 if(n==1) { putres(a[0].x,a[0].y,0); return 0; } 94 if(n==2) 95 { 96 putres( (a[0]+a[1]).x*0.5, 97 (a[0]+a[1]).y*0.5, 98 dist(a[0],a[1])*0.5); 99 100 return 0; 101 } 102 103 for(int i=0;i<n;i++) 104 { 105 int p=rand()%n; 106 swap(a[i],a[p]); 107 } 108 point O; db R=0.0; 109 for(int i=2;i<n;i++) 110 if(dist(a[i],O)>=R+eps) 111 { 112 O=a[i]; 113 R=0.0; 114 115 for(int j=0;j<i;j++) 116 if(dist(a[j],O)>=R+eps) 117 { 118 O=(a[i]+a[j])*0.5; 119 R=dist(a[i],a[j])*0.5; 120 121 for(int k=0;k<j;k++) 122 if(dist(a[k],O)>=R+eps) 123 { 124 O=cc(a[i],a[j],a[k]); 125 R=dist(a[i],O); 126 } 127 } 128 } 129 130 putres(O.x,O.y,R); 131 132 return 0; 133 }
。。。