最小圆覆盖

Click Here

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define EPS 1e-8
using namespace std;
const int maxn = 5500;
double a[maxn][5];
int n;
struct point{
    double x, y,z;
};
double ox,oy,r;
int sgn(double x)
{
    if (fabs(x) < EPS)
        return 0;
    return x < 0 ? -1 : 1;
}
double get_distance(double x1,double y1,double x2,double y2)//两点之间的距离
{ 
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 
}
void get(double ax, double ay, double bx, double by, double cx, double cy){
    double x1 = ax-bx, y1 = ay-by;
    double d1 = (ax*ax-bx*bx+ay*ay-by*by)/2;
    double x2 = ax-cx, y2 = ay-cy;
    double d2 = (ax*ax-cx*cx+ay*ay-cy*cy)/2;
    ox = (d1*y2-y1*d2)/(x1*y2-y1*x2);
    oy = (d2*x1-x2*d1)/(x1*y2-y1*x2);
    r = get_distance(ox, oy, ax, ay);
}
//p表示定点, n表示顶点的个数, c代表最小覆盖圆圆心, r是半径
double min_cover_circle(int z,int y)//找最小覆盖圆(这里没有用全局变量p[], 因为是为了封装一个函数便于调用)
{
    //random_shuffle(p, p + n);//随机函数,使用了之后使程序更快点,也可以不用
    ox=a[1][z];
    oy=a[1][y];
    r = 0;
    for (int i = 2; i <= n; i++)
    {
        if (sgn(get_distance(ox,oy,a[i][z],a[i][y]) - r) > 0)//如果p[i]在当前圆的外面, 那么以当前点为圆心开始找
        {
            ox=a[i][z];
            oy=a[i][y];
            //c = p[i];//圆心为当前点
            r = 0;//这时候这个圆只包括他自己.所以半径为0
            for (int j = 1; j < i; j++)//找它之前的所有点
            {
                if (sgn(get_distance(ox,oy,a[j][z],a[j][y]) - r) > 0)//如果之前的点有不满足的, 那么就是以这两点为直径的圆
                {
                    ox = (a[i][z]+a[j][z]) / 2.0;
                    oy = (a[i][y]+a[j][y]) / 2.0;
                    r = get_distance(ox,oy,a[j][z],a[j][y]);
                    for (int k = 1; k < j; k++)
                    {
                        if (sgn(get_distance(ox,oy,a[k][z],a[k][y])-r) > 0)//找新作出来的圆之前的点是否还有不满足的, 如果不满足一定就是三个点都在圆上了
                        {
                            get(a[i][z],a[i][y],a[j][z],a[j][y],a[k][z],a[k][y]);
                            //r = get_distance(p[i], c);
                        }
                    }
                }
            }
        }
    }
    return 2.0*r;
}
int main()
{
    
    //point p[maxn];
    //point c; double r;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        for(int j=1;j<=3;++j)
        scanf("%lf", &a[i][j]);
    random_shuffle(a+1, a+1 + n);
    double nums=min(min_cover_circle(1,2),min(min_cover_circle(1,3),min_cover_circle(2,3)));
    
    printf("%.10f\n",nums);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值