http://www.cnblogs.com/DreamUp/archive/2010/10/12/1849072.html

最小外接圆递归算法

其中 tmp = a[i];
            for (j = i; j >= 2; j--) {
                a[j] = a[j - 1];
            }
            a[1] = tmp;此处应该是随机化点集,去掉也可。

ZOJ1450 Minimal Circle 最小圆覆盖

 

包含点集所有点的最小圆的算法  http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=450 平面上有n个点,给定n个点的坐标,试找一个半径最小的圆,将n 个点全部包围,点可以在圆上。

1. 在点集中任取3点A,B,C。 2. 作一个包含A,B,C三点的最小圆,圆周可能通过这3点,也可能只通过 其中两点,但包含第3点.后一种情况圆周上的两点一定是位于圆的一条直 径的两端。 3. 在点集中找出距离第2步所建圆圆心最远的D点,若D点已在圆内或圆周上, 则该圆即为所求的圆,算法结束.则,执行第4步。 4. 在A,B,C,D中选3个点,使由它们生成的一个包含这4个点的圆为最小,这3 点成为新的A,B,C,返回执行第2步。若在第4步生成的圆的圆周只通过A,B,C,D 中的两点,则圆周上的两点取成新的A和B,从另两点中任取一点作为新的C。

 

程序设计题解上的解题报告: 对于一个给定的点集A,记MinCircle(A)为点集A的最小外接圆,显然,对于所 有的点集情况A,MinCircle(A)都是存在且惟一的。需要特别说明的是,当A为空 集时,MinCircle(A)为空集,当A={a}时,MinCircle(A)圆心坐标为a,半径为0;    显然,MinCircle(A)可以有A边界上最多三个点确定(当点集A中点的个数大于 1时,有可能两个点确定了MinCircle(A)),也就是说存在着一个点集B,|B|<=3 且B包含与A,有MinCircle(B)=MinCircle(A).所以,如果a不属于B,则 MinCircle(A-{a})=MinCircle(A);如果MinCircle(A-{a})不等于MinCircle(A),则 a属于B。     所以我们可以从一个空集R开始,不断的把题目中给定的点集中的点加入R,同 时维护R的外接圆最小,这样就可以得到解决该题的算法。

代码

#include <stdio.h>
#include <math.h>
const int maxn = 1005;
const double eps = 1e-6;
struct TPoint {
    double x, y;
    TPoint operator-(TPoint & a) {
        TPoint p1;
        p1.x = x - a.x;
        p1.y = y - a.y;
        return p1;
    }
};
struct TCircle {
    double r;
    TPoint centre;
};
struct TTriangle {
    TPoint t[3];
};
TCircle c;
TPoint a[maxn];
double distance(TPoint p1, TPoint p2) {
    TPoint p3;
    p3.x = p2.x - p1.x;
    p3.y = p2.y - p1.y;
    return sqrt(p3.x * p3.x + p3.y * p3.y);
}
double triangleArea(TTriangle t) {
    TPoint p1, p2;
    p1 = t.t[1] - t.t[0];
    p2 = t.t[2] - t.t[0];
    return fabs(p1.x * p2.y - p1.y * p2.x) / 2;
}
TCircle circumcircleOfTriangle(TTriangle t) {
    //三角形的外接圆
    TCircle tmp;
    double a, b, c, c1, c2;
    double xA, yA, xB, yB, xC, yC;
    a = distance(t.t[0], t.t[1]);
    b = distance(t.t[1], t.t[2]);
    c = distance(t.t[2], t.t[0]);
    //根据S = a * b * c / R / 4;求半径R
    tmp.r = a * b * c / triangleArea(t) / 4;

    xA = t.t[0].x;
    yA = t.t[0].y;
    xB = t.t[1].x;
    yB = t.t[1].y;
    xC = t.t[2].x;
    yC = t.t[2].y;
    c1 = (xA * xA + yA * yA - xB * xB - yB * yB) / 2;
    c2 = (xA * xA + yA * yA - xC * xC - yC * yC) / 2;

    tmp.centre.x = (c1 * (yA - yC) - c2 * (yA - yB)) /
            ((xA - xB) * (yA - yC) - (xA - xC) * (yA - yB));
    tmp.centre.y = (c1 * (xA - xC) - c2 * (xA - xB)) /
            ((yA - yB) * (xA - xC) - (yA - yC) * (xA - xB));

    return tmp;
}

TCircle MinCircle2(int tce, TTriangle ce) {
    TCircle tmp;
    if (tce == 0) tmp.r = -2;
    else if (tce == 1) {
        tmp.centre = ce.t[0];
        tmp.r = 0;
    } else if (tce == 2) {
        tmp.r = distance(ce.t[0], ce.t[1]) / 2;
        tmp.centre.x = (ce.t[0].x + ce.t[1].x) / 2;
        tmp.centre.y = (ce.t[0].y + ce.t[1].y) / 2;
    } else if (tce == 3) tmp = circumcircleOfTriangle(ce);
    return tmp;
}

void MinCircle(int t, int tce, TTriangle ce) {
    int i, j;
    TPoint tmp;
    c = MinCircle2(tce, ce);
    if (tce == 3) return;
    for (i = 1; i <= t; i++) {
        if (distance(a[i], c.centre) > c.r) {
            ce.t[tce] = a[i];
            MinCircle(i - 1, tce + 1, ce);
            tmp = a[i];//此处为洗牌,下层洗完牌后,供上层调用
            for (j = i; j >= 2; j--) {
                a[j] = a[j - 1];
            }
            a[1] = tmp;
        }
    }
}

int main() {
    //freopen("circle.in", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int n,i;
    while (scanf("%d", &n) != EOF && n) {
        for (i = 1; i <= n; i++)
            scanf("%lf%lf", &a[i].x, &a[i].y);
        TTriangle ce;
        MinCircle(n, 0, ce);
        printf("%.2lf %.2lf %.2lf\n", c.centre.x, c.centre.y, c.r);
    }
    return 0;
}

 

 

1
2 2

3
1 1
2 2
3 3

4
0 0
1 0
1 1
0 1

8
1 0
2 0
3 1
2 2
1 2
0 1
2 1
1 1

25
0 0
1 0
2 0
3 0
4 0
0 1
1 1
2 1
3 1
4 1
0 2
1 2
2 2
3 2
4 2
0 3
1 3
2 3
3 3
4 3
0 4
1 4
2 4
3 4
4 4

 2.非递归算法

转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526       by---cxlove

题目:用最小的圆覆盖所有的点

http://acm.hdu.edu.cn/showproblem.php?pid=3932

以下有两种方法。

首先是随机增量算法

 

------------------------------------------------------------------------------------

algorithm:

A、令Ci表示为前i个点的最小覆盖圆。当加入新点pi时如果pi不在Ci-1里那么pi必定在Ci的边界上。 B、再从新考虑这样一个问题,Ci为前i个点最小覆盖圆且p在Ci的的边界上!同理加入新点pi时如果p

i不在Ci-1里那么pi必定在Ci的边界上。这时我们就包含了两个点在这个最小圆的边界上。 C、再从新考虑这样一个问题,Ci为前i个点最小覆盖圆且有两个确定点再边界上!此时先让

O(N)的方法能够判定出最小圆。

------------------------------------------------------------------------------------

analysis:

现在来分析为什么是线性的。

C是线性的这是显然的。

B<-C的过程中。考虑pi 他在园内的概率为 (i-1)/i 。在圆外的概率为 1/i 所以加入pi的期望复杂度为:(1-i)/i*O(1) +(1/i)*O(i) {前者在园内那么不进入C,只用了O(1)。后者进入C用了O(i)的时间}这样分析出来,复杂度实际上仍旧

是线性的。

A<-B的过程中。考虑方法相同,这样A<-B仍旧是线性。于是难以置信的最小圆覆盖的复杂度变成了线性的。

#include<iostream>
#include<fstream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<sstream>
#include<ctime>
#include<cassert>
#define LL long long
#define eps 1e-8
#define inf 999999.0
#define zero(a) fabs(a)<eps
#define N 20
#define pi acos(-1.0)
using namespace std;
double X,Y,R;
int n;
struct Point{
    double x,y;
    Point(){}
    Point(double tx,double ty){x=tx;y=ty;}
    bool check(){
        if(x+eps>0&&y+eps>0&&x<eps+X&&y<eps+Y) return true;
        return false;
    }
}p[1005],central;
//求三点的外接圆圆心
Point Circumcenter(Point a,Point b,Point c){
    double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1)/2;
    double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2)/2;
    double d = a1 * b2 - a2 * b1;
    return Point(a.x + (c1*b2 - c2*b1)/d,a.y + (a1*c2 - a2*c1)/d);
}
double dist(Point p1,Point p2){
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
void Min_cover_circle(){
    //将点随机化
    random_shuffle(p,p+n);
    central=p[0];R=0;
    for(int i=1;i<n;i++)
        if(dist(central,p[i])+eps>R){
            central=p[i];R=0;
            for(int j=0;j<i;j++)
                if(dist(central,p[j])+eps>R){
                    central.x=(p[i].x+p[j].x)/2;
                    central.y=(p[i].y+p[j].y)/2;
                    R=dist(central,p[j]);
                    for(int k=0;k<j;k++)
                        if(dist(central,p[k])+eps>R){
                            //3点确定圆
                            central=Circumcenter(p[i],p[j],p[k]);
                            R=dist(central,p[k]);
                        }
                }
        }
}
int main(){
    while(scanf("%lf%lf%d",&X,&Y,&n)!=EOF){
        for(int i=0;i<n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        Min_cover_circle();
        printf("(%.1f,%.1f).\n%.1f\n",central.x,central.y,R);
    }
    return 0;
}