• 最小圆覆盖学习笔记


    前置知识:平面几何初步。

    最小圆覆盖

    最小圆覆盖是什么,顾名思义:给出N个点,让你画一个最小的包含所有点的圆,要求出圆的半径,及圆心的坐标。

    三点定圆大家都知道吧,唯一要求是三点不共线。

    求最小圆,就要枚举这些点,去确定圆。

    对于可(du)敬(liu)的出题人,他可不想让你这么简单的做完这个题。

    这时,我们就要用到随机增量法。

    用这个东西:random_shuffle(a+1,a+n+1);把出题人善意给你的数据顺序打乱。

    (你要问为什么?一会儿会解决吧)

    下面我们可以开始求了。三点定圆,当然要三层循环,枚举三个点。

    对于第一个点,我们让其为圆心。对于第二点我们和第一个点连线,取其中点为圆心.连线为直径,对于第三个点,我们进行三点定圆.
    来了第四个点,我们判断其是否在圆中,如果在圆中,我们继续判断,如果不在圆中,我们取一二个点,和第四个点进行三点定圆.
    因为第四个点不在前三个点的圆中.所以第四个点定的新圆一定比前三个定的圆大.
    显然,第三个点的时间复杂度是o(n)的,表面上时间复杂的是O(n^3)
    的,实际上在第一次执行完最内层循环.已经确定了一个圆。再执行外边的两层循环,就会涉及到概率.
    均摊时间复杂度O(n),具体我也不会证.

     cq(i,2,n){
            if(dis(a[i],o)>ri+eps){
                o=a[i];ri=0;
                cq(j,1,i-1){
                    if(dis(o,a[j])>ri+eps){
                        o.x=(a[i].x+a[j].x)/2;
                        o.y=(a[i].y+a[j].y)/2;
                        ri=dis(o,a[j]);
                        cq(k,1,j-1){
                            if(dis(o,a[k])>ri+eps){
                                tt(a[i],a[j],a[k]);
                            }
                        }
                    }
                }
            }
        }
    

    三点定圆

    前提是三点不共线。

    圆的一般式方程大家都知道吧:(x−x_0)2+(y−y_0)2=r^2

    我们设三个点为((x_1,y_1)),((x_2,y_2)),((x_3,y_3))带入到方程里

    [egin{cases} (x_1−x_0)^2+(y_1−y_0)^2=r^2\ (x_2−x_0)^2+(y_2−y_0)^2=r^2\ (x_3−x_0)^2+(y_3−y_0)^2=r^2\ end{cases} ]

    公式(1)(2)相减,(1)(3)相减之后经过化简可以得到:

    ((x_1−x_2)x_0+(y_1−y_2)y_0=frac{(x^2_1−x^2_2)−(y^2_2−y^2_1)}{2})
    ((x_1−x_3)x_0+(y_1−y_3)y_0=frac{(x^2_1−x^2_3)−(y^2_3−y^2_1)}{2})

    上面的式子太复杂,换一个好看一点的。

    (a=x_1−x_2)
    (b=y_1−y_2)
    (c=x_1−x_3)
    (d=y_1−y_3)
    (e=frac{(x^2_1−x^2_2)−(y^2_2−y^2_1)}{2})
    (f=frac{(x^2_1−x^2_3)−(y^2_3−y^2_1)}{2})

    那么 解得

    de−bf

    (x_0=frac{de−bf}{bc-ad})
    (y_0=frac{af−ce}{bc-ad})

    有了 x_0 和 y_0 的值后,带入(1) 式就可以得到 r的值。至此,三点确定圆的问题就解决了。

    没了
    代码如下

    void tt(Point p1,Point p2,Point p3){
        double a,b,c,d,e,f;
        a=p2.y-p1.y;
        b=p3.y-p1.y;
        c=p2.x-p1.x;
        d=p3.x-p1.x;
        f=p3.x*p3.x+p3.y*p3.y-p1.x*p1.x-p1.y*p1.y;
        e=p2.x*p2.x+p2.y*p2.y-p1.x*p1.x-p1.y*p1.y;
        o.x=(a*f-b*e)/(2*a*d-2*b*c);
        o.y=(d*e-c*f)/(2*a*d-2*b*c);
        ri=dis(o,p1);
    }
    

    完整代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define cq(i,s,n) for(int i=s;i<=n;i++)
    using namespace std;
    const double eps=1e-12;
    struct Point{
        double x,y;
    }a[500005];
    Point o;
    int n; 
    double ri;
    double dis(Point a,Point b){
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 
    }
    
    void tt(Point p1,Point p2,Point p3){
        double a,b,c,d,e,f;
        a=p2.y-p1.y;
        b=p3.y-p1.y;
        c=p2.x-p1.x;
        d=p3.x-p1.x;
        f=p3.x*p3.x+p3.y*p3.y-p1.x*p1.x-p1.y*p1.y;
        e=p2.x*p2.x+p2.y*p2.y-p1.x*p1.x-p1.y*p1.y;
        o.x=(a*f-b*e)/(2*a*d-2*b*c);
        o.y=(d*e-c*f)/(2*a*d-2*b*c);
        ri=dis(o,p1);
    }
    
    int main(){
        scanf("%d",&n);
        cq(i,1,n){
            scanf("%lf%lf",&a[i].x,&a[i].y);
        }
        random_shuffle(a+1,a+n+1);
        o=a[1];ri=0;
        cq(i,2,n){
            if(dis(a[i],o)>ri+eps){
                o=a[i];ri=0;
                cq(j,1,i-1){
                    if(dis(o,a[j])>ri+eps){
                        o.x=(a[i].x+a[j].x)/2;
                        o.y=(a[i].y+a[j].y)/2;
                        ri=dis(o,a[j]);
                        cq(k,1,j-1){
                            if(dis(o,a[k])>ri+eps){
                                tt(a[i],a[j],a[k]);
                            }
                        }
                    }
                }
            }
        }
        printf("%.10lf
    %.10lf %.10lf",ri,o.x,o.y);
        return 0;
    }
    

    ({Hugecolor{Salmon}{习题}})(话说可以算成双倍经验)

    P2533 [AHOI2012]信号塔
    P1742 最小圆覆盖

  • 相关阅读:
    netcore一键部署到linux服务器以服务方式后台运行
    查找100-999之间的水仙花数
    shell创建数据库的脚本
    python打印九九乘法表的菱形实现
    c++一些重要的细节
    MySQL数据库基础学习笔记(二)
    MySQL数据库基础学习笔记(一)
    react-redux 的基本使用
    react-router-dom基本使用+3种传参方式
    从create-react-app 项目搭建开始
  • 原文地址:https://www.cnblogs.com/enceladus-return0/p/9632523.html
Copyright © 2020-2023  润新知