描述
平面上n个点,包含这n个点(点可以在圆的边界)的圆称为这n个点的覆盖圆,求这n个点的半径最小的覆盖圆,输出该圆的圆心坐标和半径。
输入
第一行是整数n,表示点数。后面是n个点的坐标。0<n<5000
n
x1 y1
x2 y2
,
xn yn
输出
输出n个点的最小覆盖圆,圆心坐标和半径。保留五位小数
输入样例 1
3
0 0
0 3000
4000 0
输出样例 1
2000.00000 1500.00000 2500.00000
输入样例 2
9
200 400
300 400
300 300
400 300
400 400
500 400
500 200
350 200
200 200
输出样例 2
350.00000 300.00000 180.27756
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define eps 1e-8
using namespace std;
struct point{
double x,y;
};
point c;
point p[5005];
double r;
double dist(point a,point b){
return sqrt(pow((a.x-b.x),2)+pow((a.y-b.y),2));
}
void circle1(point a,point b){
c.x=(a.x+b.x)/2;
c.y=(a.y+b.y)/2;
r=sqrt(pow((a.x-c.x),2)+pow((a.y-c.y),2));
}
void circle2(point p1,point p2,point p3){
//根据克拉默法则求外接圆的圆心坐标(x0,y0),以及半径r
double a1 = 2*(p2.x - p1.x);
double b1 = 2*(p2.y - p1.y);
double c1 = p2.x*p2.x + p2.y*p2.y - p1.x*p1.x - p1.y*p1.y;
double a2 = 2*(p3.x - p2.x);
double b2 = 2*(p3.y - p2.y);
double c2 = p3.x*p3.x + p3.y*p3.y - p2.x*p2.x - p2.y*p2.y;
c.x = ((c1*b2) - (c2*b1)) / ((a1*b2) - (a2*b1));
c.y = ((a1*c2) - (a2*c1)) / ((a1*b2) - (a2*b1));
r = dist(c, p1);
}
main(){
int n; cin >> n;
for(int i=0;i<n;i++)
cin>>p[i].x>>p[i].y;
c=p[0];r=0;
//试探边界
for(int i=1;i<n;i++)
if(dist(c,p[i])>r){//新点,不在原覆盖圆里
circle1(p[0],p[i]);//寻找新覆盖圆
for(int j=1;j<i;j++)
if(dist(c,p[j])>r){//判断原来的点是否在新的覆盖圆里
circle1(p[j],p[i]);//不在,产生新的覆盖圆
for(int k=0;k<j;k++)
if(dist(c,p[k])>r)//若还不在则使用三个点来构造圆
circle2(p[k],p[i],p[j]);
}
}
printf("%.5lf %.5lf %.5lf",c.x,c.y,r);
}