zoukankan      html  css  js  c++  java
  • 最小圆覆盖(随机增量法)

    原理:

    设前k个点的最小覆盖圆为Ck

    在前i-1个点的最小覆盖圆C(i-1)的基础上

    Ⅰ 第i个点不被C(i-1)覆盖,则点i一定在Ci上,做固定了点i、前i个点的最小圆覆盖

      初始让Ci的圆心为点i,0为半径,然后逐步把前i-1个点加到Ci内

      枚举点j,j∈[1,i-1]

      1.点j不被Ci覆盖,则构建一个新的Cj,点i和点j一定在Cj上,做固定了点i j,前j个点的最小圆覆盖

        初始让Cj的圆心为i和j的中点,i和j距离的一半为半径,然后逐步把前j-1个点加到Cj内

        枚举点k,k∈[1,j-1]

          a. 点k不被Cj覆盖,则构建一个新的Ck,点i,j,k一定可以构成一个圆,此时的圆覆盖了i j 和 前k个点

          b. 点k被Cj覆盖,Cj不变

      2.点j被Ci覆盖,Ci不变

    Ⅱ 第i个点被C(i-1)覆盖,Ci=C(i-1)

    时间复杂度:

    假设随机产生n个点,最小覆盖圆是C。因为三点共圆,当第n个点落在C的那3个点上时,说明C是重构的。

    所以随机生成n个点,最后一个点不在前n-1个点的最小覆盖圆上的概率为3/n

    总复杂度为线性的

    要把原先点的顺序随机打乱

    如果ijk三点幸运的共线了,可以取他们较远的两个点的中点为圆心

    #include<cstdio> 
    #include<cmath>
    #include<algorithm>
    
    using namespace std;
    
    #define N 1000001
    
    struct Point
    {
        double x,y;
    }e[N]; 
    
    struct Circle
    {
        Point c;
        double r;
    }a;
    
    double dis(Point a,Point b)
    {
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    
    Circle mid(Point a,Point b)
    {
        Circle o;
        o.c.x=(a.x+b.x)/2;
        o.c.y=(a.y+b.y)/2;
        o.r=dis(a,b)/2;
        return o;
    }
    
    Circle work(Point A,Point B,Point C)
    {
        double a=B.x-A.x;
        double b=C.x-A.x;
        double c=B.y-A.y;
        double d=C.y-A.y;
        double e=(B.x*B.x-A.x*A.x+B.y*B.y-A.y*A.y)/2;
        double f=(C.x*C.x-A.x*A.x+C.y*C.y-A.y*A.y)/2;
        Circle cc;
        double m=a*d-b*c;
        if(abs(m)<1e-4)
        {
            double dis1=dis(A,C);
            double dis2=dis(B,C);
            if(dis1>dis2) return mid(A,C);
            return mid(B,C);
        }
        cc.c.x=(e*d-c*f)/m;
        cc.c.y=(a*f-b*e)/m;
        cc.r=dis(cc.c,A);
        return cc;
    }
    
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i) scanf("%lf%lf",&e[i].x,&e[i].y);
        random_shuffle(e+1,e+n+1);
        a.c=e[1];
        for(int i=2;i<=n;++i)
            if(dis(e[i],a.c)>a.r) 
            {
                a.c=e[i];
                a.r=0;
                for(int j=1;j<i;++j)
                    if(dis(e[j],a.c)>a.r)
                    {
                        a=mid(e[i],e[j]);
                        for(int k=1;k<j;++k)
                        {
                            if(dis(e[k],a.c)>a.r)
                                a=work(e[i],e[j],e[k]);
                        //    printf("i=%d j=%d k=%d : %.2lf %.2lf %.2lf 
    ",i,j,k,a.c.x,a.c.y,a.r);
                        } 
                    }
            }
        printf("%.2lf %.2lf %.2lf",a.c.x,a.c.y,a.r);
    }
    作者:xxy
    本文版权归作者和博客园共有,转载请用链接,请勿原文转载,Thanks♪(・ω・)ノ。
  • 相关阅读:
    Java中遍历Set集合的方法
    分布式RPC框架Apache Dubbo
    CSS:页面美化和布局控制
    JavaScript实例
    Codeforces Round #604 题解
    洛谷P1533 可怜的狗狗题解
    Educational Codeforces Round 81 题解
    P1494 [国家集训队]小Z的袜子 题解
    洛谷P1283 平板涂色题解
    洛谷P1220 关路灯题解
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/14518258.html
Copyright © 2011-2022 走看看