ZOJ 1450 Minimal Circle 求最小覆盖圆

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.0
double 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 1100
struct 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;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值