其他分享
首页 > 其他分享> > 解析几何--最小圆覆盖

解析几何--最小圆覆盖

作者:互联网

最小圆覆盖问题指平面上有n个点,给定n个点的坐标,找到一个半径最小的圆,将n个点全部包围,点可以在圆上。

求最小圆覆盖问题的方法有很多种。一步一步学习。

先介绍增量法的实现步骤。

点增量法

(1)在点集中任取三点A,B,C。

(2)做一个包含A,B,C三点的小圆,圆周可能通过这三点,也可能只通过其中两个点,但包含第三个点。后一种情况,圆周上两点一定位于圆的一条直径的两端。

(3)在点集中找出距离(2)所建圆圆心最远的D点,若D点已在园内||圆周上,则该圆即为所求的圆,算法结束,否则执行(4)

(4)在A,B,C,D中选三个点,使由他们生成的一个包含这四个点的圆最小,这三点成为新的A,B,C,返回(2),若(4)生成的圆的圆周只通过A,B,C,D中的两点,则圆周上的两点取成新的A和B,从另两点中任取一点作为新的C。

三角形增量法

(1)任意选择两点Pi,Pj,然后以Pi,Pj为端点,Pi,Pj的中点为圆心,构造一个圆。如果这个圆包括所有的点,那么他就是最小的圆。中点也就是最小圆的圆心;否则选择圆外一点Pk;

(2)如果Pi,Pj,Pk三点形成的三角形是直角或钝角三角形,那么该直角||钝角三角形所对应的两点为Pi,Pj,然后再次重新构建一个以新Pi,Pj为直径的圆,重复(1)的步骤;否则,这三点形成一个锐角三角形,构造一个外接圆,如果这个圆包含所有的点,结束。否则进入(3)

(3)选择一些不在园内的点Pl,设点Q为{Pi,Pj,Pk}中离Pl最远的点,连接并延长点Pl和Q,将平面分成两个半平面,设顶点R为{Pi,Pj,Pk}中与Pl不在一个半平面中的点,得到Pl,Q,R三点,返回(1)。

Code:以HDU-3007-Buried memory(板子)为例

// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
//#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
const double PI=acos(-1.0);
const double EPS=1.0e-8;

struct Point{
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x;y=_y;
	}
	friend Point operator + (const Point &a,const Point &b){
		return Point(a.x+b.x,a.y+b.y);
	}
	friend Point operator - (const Point &a,const Point &b){
		return Point(a.x-b.x,a.y-b.y);
	}
	friend double operator ^ (Point a,Point b){
		return a.x*b.y-a.y*b.x;
	}
}Dots[MAXN],Dots2[MAXN];
struct V{
	Point start,end;double ang;
	V(Point _start=Point(0,0),Point _end=Point(0,0),double _ang=0.0){
		start=_start;end=_end;ang=_ang;
	}
	friend V operator + (const V &a,const V &b){
		return V(a.start+b.start,a.end+b.end);
	}
	friend V operator - (const V &a,const V &b){
		return V(a.start-b.start,a.end-b.end);
	}
}Edge[MAXN],Edge2[MAXN],stk[MAXN];
struct Circle{
	double r;
	Point centre;
	Circle(Point _centre=Point(0,0),double _r=0){
		centre=_centre;r=_r;
	}
}ansC;
struct Triangle{
	Point p[3];
};
int n;


int Parellel(const V &x,const V &y){
	return fabs((x.end-x.start)^(y.end-y.start))<EPS;
}
Point LineInterDot(const V &l1,const V &l2){
	Point p;
	double S1=(l2.end-l1.start)^(l2.start-l1.start);
	double S2=(l2.start-l1.end)^(l2.end-l1.end);
	p.x=(l1.start.x*S2+l1.end.x*S1)/(S1+S2);
	p.y=(l1.start.y*S2+l1.end.y*S1)/(S1+S2);
	return p;
}
double Distance(Point p1,Point p2){
	p2=p2-p1;
	return sqrt(p2.x*p2.x+p2.y*p2.y);
}
double TriangleArea(Triangle t){
	return fabs((t.p[1]-t.p[0])^(t.p[2]-t.p[0]))/2.0;
}
Circle CircumCircleOfTriangle(const Triangle &t){
	Circle tmp;
	double a,b,c,c1,c2;
	double xa,ya,xb,yb,xc,yc;
	a=Distance(t.p[0],t.p[1]);b=Distance(t.p[1],t.p[2]);c=Distance(t.p[2],t.p[0]);
	tmp.r=a*b*c/TriangleArea(t)/4.0;
	xa=t.p[0].x;ya=t.p[0].y;
	xb=t.p[1].x;yb=t.p[1].y;
	xc=t.p[2].x;yc=t.p[2].y;
	c1=(xa*xa+ya*ya-xb*xb-yb*yb)/2.0;
	c2=(xa*xa+ya*ya-xc*xc-yc*yc)/2.0;
	tmp.centre.x=(c1*(ya-yc)-c2*(ya-yb))/((xa-xb)*(ya-yc)-(xa-xc)*(ya-yb));
	tmp.centre.y=(c1*(xa-xc)-c2*(xa-xb))/((ya-yb)*(xa-xc)-(ya-yc)*(xa-xb));
	return tmp;
}
Circle MinCircle2(int u,Triangle t){
	if(u==0) return Circle(Point(0,0),-2.0);
	else if(u==1) return Circle(t.p[0],0);
	else if(u==2) return Circle(Point((t.p[0].x+t.p[1].x)/2.0,(t.p[0].y+t.p[1].y)/2.0),Distance(t.p[0],t.p[1])/2.0);
	else if(u==3) return CircumCircleOfTriangle(t);
}
void MinCircle(int n,int u,Triangle t){
	ansC=MinCircle2(u,t);
	if(u==3) return ;
	for(int i=1;i<=n;++i){
		if(Distance(Dots[i],ansC.centre)>ansC.r){
			t.p[u]=Dots[i];
			MinCircle(i-1,u+1,t);
			Point temp=Dots[i];
			for(int j=i;j>=2;--j){
				Dots[j]=Dots[j-1];
			}Dots[1]=temp;
		}
	}
}
int main(){
	int n;
	while(~scanf("%d",&n)){
		if(n==0) break;
		for(int i=1;i<=n;++i){
			scanf("%lf%lf",&Dots[i].x,&Dots[i].y);
		}Triangle t;
		MinCircle(n,0,t);
		printf("%.2lf %.2lf %.2lf\n",ansC.centre.x,ansC.centre.y,ansC.r);
	}
}
/*

*/

 

标签:Dots,三点,Pi,覆盖,最小,解析几何,Pj,include,Pl
来源: https://blog.csdn.net/qq_40482358/article/details/88026033