求最小圆覆盖

https://blog.csdn.net/niiick/article/details/89153096

主要是看这一篇博客写的。

本来是想,是不是什么模拟退火,二分查找,随机搜索什么的算法。

但是最后不是,,,根据点的随机分布而得到了O(n^3)到线性时间的算法???

 

就是最小圆覆盖一定是两个点或者三个点而确定的。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
const double eps=1e-6;
struct point
{
    double x;
    double y;
}p[1005];
double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double R;//维护的圆的半径
point get_p0(point p1,point p2,point p3)
{
    double a=p2.x-p1.x;
    double b=p2.y-p1.y;
    double c=p3.x-p2.x;
    double d=p3.y-p2.y;
    double e=p2.x*p2.x-p1.x*p1.x-p1.y*p1.y+p2.y*p2.y;
    double f=p3.x*p3.x-p2.x*p2.x-p2.y*p2.y+p3.y*p3.y;
    double x0=(f*b-e*d)/(c*b-a*d)/2;
    double y0=(a*f-e*c)/(a*d-b*c)/2;
    //R=dis(point{x0,y0},p1);
    return point{x0,y0};
}
int n;
point work()
{
    point p0=p[1];
    R=0;
    for(int i=1;i<=n;i++)
    {
        if(dis(p[i],p0)-R>eps)
        {
            p0=p[i];//很容易理解,需要将这个新的点纳入考虑。
            R=0;
            for(int j=1;j<i;j++)//按照几何结论,首先考虑两个点都在圆心的情况
            {
                if(dis(p[j],p0)-R>eps)
                {
                    p0=point{(p[i].x+p[j].x)/2,(p[i].y+p[j].y)/2};
                    R=dis(p0,p[i]);
                    for(int k=1;k<j;k++)
                    {
                        if(dis(p[k],p0)-R>eps)
                        {
                            p0=get_p0(p[i],p[j],p[k]);
                            R=dis(p0,p[k]);
                        }
                    }
                }
            }
        }
    }
    return p0;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>p[i].x>>p[i].y;
        }
        point ans=work();
        //输出坐标半径
        printf("%.2lf %.2lf %.2lf\n",ans.x,ans.y,R);
    }
    return 0;
}

看起来是很暴力的做法,几何计算倒是很基础。就是三点确定圆心坐标有点难算。

posted @ 2020-12-28 21:09  TheDa  阅读(82)  评论(0编辑  收藏  举报