hdu3007

求一个半径最小的圆覆盖住所有点

使用随机增量的方法,每次找到一个不在当前圆内的点,将圆调整扩大至该点在圆周上,期望复杂度O(n)。注意在调用getMinCover之前应先把point[]中的点打乱顺序。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
const int MAXN = 505;
const double EPS = 1e-6;
double PI;
struct Point
{
    Point() {}
    Point(double _x, double _y): x(_x), y(_y) {}
    double getDis(Point rhs)
    {
        double xx = rhs.x - x, yy = rhs.y - y;
        return sqrt(xx * xx + yy * yy);
    }

    void input(){scanf("%lf%lf", &x, &y);}
    double x, y;
};
double operator ^(Point lhs, Point rhs){return lhs.x * rhs.y - lhs.y * rhs.x;}
Point operator +(Point lhs, Point rhs){return Point(lhs.x + rhs.x, lhs.y + rhs.y);}
Point operator -(Point lhs, Point rhs){return Point(lhs.x - rhs.x, lhs.y - rhs.y);}
Point operator /(Point lhs, double rhs){return Point(lhs.x / rhs, lhs.y / rhs);}
Point operator *(Point lhs, double rhs){return Point(lhs.x * rhs, lhs.y * rhs);}

Point point[MAXN];
int n;
Point center;
double radius;

bool isPointInCircle(Point &t)
{
    return t.getDis(center) <= radius + EPS;
}

void adjustCircleCenter(Point &p0, Point &p1, Point &p2)
{
    double a1 = p1.x - p0.x, b1 = p1.y - p0.y, c1 = (a1 * a1 + b1 * b1) / 2.0;
    double a2 = p2.x - p0.x, b2 = p2.y - p0.y, c2 = (a2 * a2 + b2 * b2) / 2.0;
    double d = a1 * b2 - a2 * b1;
    center.x = p0.x + (c1 * b2 - c2 * b1) / d;
    center.y = p0.y + (a1 * c2 - a2 * c1) / d;
}

void getMinCircleCover()
{
    radius = 0.0;
    center = point[0];
    for(int i = 1; i < n; ++i)
    {
        if(!isPointInCircle(point[i]))
        {
            center = point[i];
            radius = 0;
            for(int j = 0; j < i; ++j)
            {
                if(!isPointInCircle(point[j]))
                {
                    center = (point[i] + point[j]) / 2.0;
                    radius = center.getDis(point[j]);
                    for(int k = 0; k < j; ++k)
                    {
                        if(!isPointInCircle(point[k]))
                        {
                            adjustCircleCenter(point[i], point[j], point[k]);
                            radius = center.getDis(point[k]);
                        }
                    }
                }
            }
        }
    }
}

int main()
{
    while(scanf("%d", &n) && n != 0)
    {
        for(int i = 0; i < n; ++i) point[i].input();
        getMinCircleCover();
        printf("%.2lf %.2lf %.2lf\n", center.x, center.y, radius);
    }
}