[最小圆覆盖] ——Minimal Circle ZOJ - 1450

问题虫洞: Minimal Circle ZOJ - 1450

黑洞内窥:

给出n个点,求最小圆覆盖完所有的点,

输出圆心座标、半径;

 

最小圆覆盖问题:推荐博客:最小圆覆盖

算法步骤:

最优解的圆一定是以某两个点连线为直径的圆某三个点组成的三角形的外接圆
初始将圆心定为第一个点,R=0
1.枚举第一个点 i,若点 i 不在目前圆内,设它为圆心,进入2
2.再枚举第二个点 j,若点 j 不在当前圆内,设当前圆为以 i,j 为直径的圆,进入3
3.枚举第三个点 k,若点 k 不在当前圆内,设当前圆为 i,j,k 的外接圆

看似O(n3)的复杂度,但点集随机打乱后期望复杂度O(n)。

 

random_shuffle函数的作用:

  将[first,last)的元素次序随机重排。N个元素的排列方式共有N!种,

random_shuffle会产生一个均匀分布,因此任何一个排列被选中的概率为1/N!。

 

三点定圆的推导:

 

上面的模板题ACcode:

#include<stdio.h>
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define MAXN 100005
#define INF 0x3f3f3f3f//将近int类型最大数的一半,而且乘2不会爆int
#define MOD 1000000007 // MOD%4 = 3
const double pi = acos(-1.0);
const double eps = 1e-6;

int n;
double r;               ///r为最小圆半径,n为所有覆盖点点数
struct point
{
    double x, y;
}a[MAXN], o;            ///o为最小圆的圆心座标

double distance(point p1, point p2)
{
    return sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));
}

void circum(point p1, point p2, point p3)///三点定圆
{
    double a, b, c, d, e, f;
    a = 2*(p2.x - p1.x);
    b = 2*(p2.y - p1.y);
    c = p2.x*p2.x + p2.y*p2.y - p1.x*p1.x - p1.y*p1.y;
    d = 2*(p3.x - p1.x);
    e = 2*(p3.y - p1.y);
    f = p3.x*p3.x + p3.y*p3.y - p1.x*p1.x - p1.y*p1.y;
    o.x = (b*f - e*c)/(b*d - e*a);
    o.y = (d*c - a*f)/(b*d - e*a);
    r = distance(p1, o);
}

void mincir()                   ///最小圆覆盖
{
    o=a[1], r=0;
    for(int i=2; i<=n; ++i)
    {
        if(distance(o, a[i]) > r+eps)
        {
            o=a[i], r=0;
            for(int j=1; j<=i-1; ++j)
            {
                if(distance(o, a[j]) > r+eps)
                {
                    o.x = (a[i].x+a[j].x)/2;
                    o.y = (a[i].y+a[j].y)/2;
                    r = distance(o, a[j]);
                    for(int k=1; k<=j-1; ++k)
                        if(distance(o, a[k]) > r+eps)
                            circum(a[i], a[j], a[k]);
                }
            }
        }
    }
}

int main()
{
    while(cin >> n && n)
    {
        for(int i=1; i<=n; ++i)
            scanf("%lf %lf", &a[i].x, &a[i].y);
        random_shuffle(a+1,a+1+n);          ///随机重拍,这里可不要。
        mincir();
        printf("%.2f %.2f %.2f\n", o.x, o.y, r);
    }
    return 0;
}

 

发布了165 篇原创文章 · 获赞 35 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章