[最小圓覆蓋] ——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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章