最小覆盖圆

给出一堆点,求一个面积(半径)最小的圆,使得所有点都在它的内部或边界上.

随机增量法是这样的....

先随机打乱点的顺序......

然后,我们假设已经得到了点 $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$ 对应的外接圆.

于是我们就得到了一个覆盖了点 $1,2,...,k$ 的,经过点 $j+1,i+1$ 的最小覆盖圆. 当我们的指针 $k$ 扫完 $1,2,...,j$ 的时候,我们就求出了覆盖点 $1,2,...,j,j+1$ 的,经过点 $i+1$ 的最小覆盖圆. 当我们的指针 $j$ 扫完 $1,2,...,i$ 的时候,我们就求出了点 $1,2,...,i,i+1$ 的最小覆盖圆.

代码非常的暴力,把点集随机打乱以后就可以 $O(n)$ 了...


另外怎么证明,最小覆盖圆只能有一个?

 

 

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 }
View Code

 

 

。。。

posted @ 2015-06-11 15:02  DragoonKiller  阅读(990)  评论(4编辑  收藏  举报