求最小圆覆盖
https://blog.csdn.net/niiick/article/details/89153096
主要是看这一篇博客写的。
本来是想,是不是什么模拟退火,二分查找,随机搜索什么的算法。
但是最后不是,,,根据点的随机分布而得到了O(n^3)到线性时间的算法???
就是最小圆覆盖一定是两个点或者三个点而确定的。
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> using namespace std; const double eps=1e-6; struct point { double x; double y; }p[1005]; double dis(point a,point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double R;//维护的圆的半径 point get_p0(point p1,point p2,point p3) { double a=p2.x-p1.x; double b=p2.y-p1.y; double c=p3.x-p2.x; double d=p3.y-p2.y; double e=p2.x*p2.x-p1.x*p1.x-p1.y*p1.y+p2.y*p2.y; double f=p3.x*p3.x-p2.x*p2.x-p2.y*p2.y+p3.y*p3.y; double x0=(f*b-e*d)/(c*b-a*d)/2; double y0=(a*f-e*c)/(a*d-b*c)/2; //R=dis(point{x0,y0},p1); return point{x0,y0}; } int n; point work() { point p0=p[1]; R=0; for(int i=1;i<=n;i++) { if(dis(p[i],p0)-R>eps) { p0=p[i];//很容易理解,需要将这个新的点纳入考虑。 R=0; for(int j=1;j<i;j++)//按照几何结论,首先考虑两个点都在圆心的情况 { if(dis(p[j],p0)-R>eps) { p0=point{(p[i].x+p[j].x)/2,(p[i].y+p[j].y)/2}; R=dis(p0,p[i]); for(int k=1;k<j;k++) { if(dis(p[k],p0)-R>eps) { p0=get_p0(p[i],p[j],p[k]); R=dis(p0,p[k]); } } } } } } return p0; } int main() { int T; cin>>T; while(T--) { cin>>n; for(int i=1;i<=n;i++) { cin>>p[i].x>>p[i].y; } point ans=work(); //输出坐标半径 printf("%.2lf %.2lf %.2lf\n",ans.x,ans.y,R); } return 0; }
看起来是很暴力的做法,几何计算倒是很基础。就是三点确定圆心坐标有点难算。