ZOJ 1450 Minimal Circle 求最小覆盖圆

来源:互联网 发布:yum y install wget 编辑:程序博客网 时间:2024/05/17 03:42

ZOJ 1450 Minimal Circle

You are to write a program to find a circle which covers a set of points and has the minimal area. There will be no more than 100 points in one problem.


Input

The input contains several problems. The first line of each problem is a line containing only one integer N which indicates the number of points to be covered. The next N lines contain N points. Each point is represented by x and y coordinates separated by a space. After the last problem, there will be a line contains only a zero.


Output

For each input problem, you should give a one-line answer which contains three numbers separated by spaces. The first two numbers indicate the x and y coordinates of the result circle, and the third number is the radius of the circle. (use escape sequence %.2f)


Sample Input

2
0.0 0.0
3 0
5
0 0
0 1
1 0
1 1
2 2
0


Sample Output

1.50 0.00 1.50
1.00 1.00 1.41

如图:已知三点可确定一圆。

垂直平分线方程:

DO:y=(x1-x2)/(y2-y1)*(x-(x1+x2)/2)+(y1+y2)/2

OE:y=(x1-x3)/(y3-y1)*(x-(x1+x3)/2)+(y1+y3)/2

X0=(0.5*(x1*x1-x2*x2)/(y2-y1)-0.5*(x1*x1-x3*x3)/(y3-y1)+(y3-y2)/2.0)/((x1-x2)/(y2-y1)-(x1-x3)/(y3-y1))

y0=(0.5*(y1*y1-y2*y2)/(x2-x1)-0.5*(y1*y1-y3*y3)/(x3-x1)+(x3-x2)/2.0)/((y1-y2)/(x2-x1)-(y1-y3)/(x3-x1))

半径:r=hypot((x1-x0),(y1-y0))

自己写的效率很低:(760ms AC)

#include<stdio.h>#include<math.h>#define INF 999999999.0double x[101],y[101];double dis(double x1,double y1,double x2,double y2){double dx=x1-x2;//if(dx<0)dx=-dx;double dy=y1-y2;//if(dy<0)dy=-dy;double d=hypot(dx,dy);return d;}double pot(double x1,double y1,double x2,double y2,double x3,double y3){double x0=(0.5*(x1*x1-x2*x2)/(y2-y1)-0.5*(x1*x1-x3*x3)/(y3-y1)+(y3-y2)/2.0)/((x1-x2)/(y2-y1)-(x1-x3)/(y3-y1));return x0;}int main(){int n,i,j,k,q;double xx,yy;while(scanf("%d",&n)&& n!=0){for(i=0;i<n;i++)scanf("%lf%lf",&x[i],&y[i]);//记得&double minr=INF;for(i=0;i<n;i++)//先判断两点确定一圆for(j=i+1;j<n;j++){if(i==j) continue;int ok=1;double r=dis(x[i],y[i],x[j],y[j])/2;double x0=(x[i]+x[j])/2;double y0=(y[i]+y[j])/2;for(k=0;k<n;k++){if(k==i||k==j) continue;double d=dis(x0,y0,x[k],y[k]);if(r>=d) continue;else {ok=0;break;}}if(ok && r<minr) {minr=r;xx=x0,yy=y0;}}for(i=0;i<n;i++)//再判断三点确定一圆for(j=i+1;j<n;j++)for(k=j+1;k<n;k++){int ok=1;double x0=pot(x[i],y[i],x[j],y[j],x[k],y[k]);double y0=pot(y[i],x[i],y[j],x[j],y[k],x[k]);double r=dis(x[i],y[i],x0,y0);for(q=0;q<n;q++){if(q==i||q==j||q==k) continue;double d=dis(x0,y0,x[q],y[q]);if(r>=d) continue;else {ok=0;break;}}if(ok && r<minr) {minr=r;xx=x0,yy=y0;}}printf("%.2lf %.2lf %.2lf\n",xx,yy,minr);}return 0;}


别人的(0ms AC) = = !

#include<stdio.h>#include<string.h>#include<math.h>#define PR 1e-6#define N 1100struct TPoint{    double x,y;}ply[N];struct TCircle{    TPoint p;    double r;}cir;struct TTriangle{    TPoint t[3];}tri;int n;double r;int dblcmp(double a){    if(fabs(a)<PR) return 0;    else return a>0?1:-1;}double dist(TPoint a,TPoint b)//距离{    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double det(double a1,double b1,double a2,double b2)//叉积{    return a1*b2-a2*b1;}double cross(TPoint a,TPoint b,TPoint c)//叉积{    return det(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);}double trianglearea(TTriangle ti)//三角形面积{    return fabs(cross(ti.t[0],ti.t[1],ti.t[2]))*0.5;}void mintricir(TTriangle ti){    double t1,t2,t3,c1,c2,c3;    double xA,xB,xC,yA,yB,yC;    int d=dblcmp(cross(ti.t[0],ti.t[1],ti.t[2]));    t1=dist(ti.t[0],ti.t[1]);    t2=dist(ti.t[1],ti.t[2]);    t3=dist(ti.t[0],ti.t[2]);        xA=ti.t[0].x;        xB=ti.t[1].x;        xC=ti.t[2].x;        yA=ti.t[0].y;        yB=ti.t[1].y;        yC=ti.t[2].y;        c1=(xA*xA+yA*yA-xB*xB-yB*yB)/2;        c2=(xA*xA+yA*yA-xC*xC-yC*yC)/2;        c3=(xA-xB)*(yA-yC)-(xA-xC)*(yA-yB);        cir.p.x=(c1*(yA-yC)-c2*(yA-yB))/c3;        cir.p.y=(c1*(xA-xC)-c2*(xA-xB))/(-c3);        cir.r=t1*t2*t3/trianglearea(ti)/4.0;    //}}void getmincircle(int t,TTriangle ti)//确定过三角形ti的圆{    if(t==0) cir.r=-1;//点0    else if(t==1) cir.p=ti.t[0],cir.r=0;//点1    else if(t==2)//点2    {        cir.p.x=(ti.t[0].x+ti.t[1].x)/2;        cir.p.y=(ti.t[0].y+ti.t[1].y)/2;        cir.r=dist(ti.t[0],ti.t[1])/2;    }    else mintricir(ti);//点3}void mincircle(int m,int t,TTriangle ti){    int i,j;    getmincircle(t,ti);//确定最小半径    if(t==3) return ;    for(j=1;j<=m;j++)    {        double l=dist(cir.p,ply[j]);        if((dblcmp(l-cir.r))<=0) continue;//如果j点在圆内        ti.t[t]=ply[j];//更新        mincircle(j-1,t+1,ti);//继续       }}int main(){    while(scanf("%d",&n),n)    {        int i;        for(i=1;i<=n;i++) scanf("%lf%lf",&ply[i].x,&ply[i].y);//输入n个点        mincircle(n,0,tri);//求最小半径        printf("%.2lf %.2lf %.2lf\n",cir.p.x,cir.p.y,cir.r);    }    return 0;}