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;
}