• 最小覆盖圆


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

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

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

    然后,我们假设已经得到了点 $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
    ",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

     

     

    。。。

  • 相关阅读:
    利用burpsuite实现重放攻击
    木马分析(隐藏分析)实验
    使用wireshark分析TLS
    ECharts折线图循环展示数据、自定义色值(渐变)
    Sumblime Text3格式化代码
    ECharts柱状图彩色柱状图(渐变),自定义鼠标移入小圈颜色、鼠标移入后提示框显示不全问题、渲染到页面中
    C#多线程学习(五) 多线程的自动管理(定时器)
    SQL取出 所有周六 周日的日期
    C#多线程学习(二) 如何操纵一个线程
    简单读写XML文件
  • 原文地址:https://www.cnblogs.com/DragoonKiller/p/4569142.html
Copyright © 2020-2023  润新知