bzoj 1337: 最小圆覆盖 (最小圆覆盖)

1337: 最小圆覆盖

Time Limit: 1 Sec   Memory Limit: 64 MB
Submit: 939   Solved: 463
[ Submit][ Status][ Discuss]

Description

给出平面上N个点,N<=10^5.请求出一个半径最小的圆覆盖住所有的点

Input

第一行给出数字N,现在N行,每行两个实数x,y表示其坐标.

Output

输出最小半径,输出保留三位小数.

Sample Input

4
1 0
0 1
0 -1
-1 0

Sample Output

1.000

HINT

Source

[ Submit][ Status][ Discuss]


题解:随机增量法求最小圆覆盖

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 100005
#define eps 1e-7
using namespace std;
int n,m;
struct vector {
	double x,y;
	vector (double X=0,double Y=0){
		x=X,y=Y;
	}
}p[N],tmp;
double x,y,ans,r,pi=acos(-1.0);
typedef vector point;
vector operator -(vector a,vector b){
	return vector (a.x-b.x,a.y-b.y);
}
vector operator +(vector a,vector b){
	return vector (a.x+b.x,a.y+b.y);
}
vector operator *(vector a,double t){
	return vector (a.x*t,a.y*t);
}
vector operator /(vector a,double t){
	return vector (a.x/t,a.y/t);
}
int dcmp(double x)
{
	if (fabs(x)<eps) return 0;
	return x<0?-1:1;
}
double len(vector a)
{
	return sqrt(a.x*a.x+a.y*a.y);
}
double cross(vector a,vector b)
{
	return a.x*b.y-a.y*b.x;
}
point glt(point a,vector v,point b,vector w)
{
	vector u=a-b;
	double t=cross(w,u)/cross(v,w);
	return a+v*t;
}
vector rotate(vector a,double rad)
{
	return vector (a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
}
point center(point a,point b,point c)
{
	point p=(a+b)/2; point q=(a+c)/2;
	vector v=rotate(b-a,pi/2); vector u=rotate(c-a,pi/2);
	if (dcmp(cross(v,u))==0) {
		if (dcmp(len(a-b)+len(c-b)-len(a-c))==0) return (a+c)/2;
		if (dcmp(len(a-c)+len(c-b)-len(a-b))==0) return (a+b)/2;
		if (dcmp(len(c-a)+len(a-b)-len(c-b))==0) return (b+c)/2;
	}
	return glt(p,v,q,u);
}
double mincc()
{
	random_shuffle(p,p+n);
	double r=0;
	point c=p[0];
	for (int i=1;i<n;i++)
	if (dcmp(len(p[i]-c)-r)>0){
		c=p[i]; r=0;
		for (int j=0;j<i;j++)
		 if (dcmp(len(p[j]-c)-r)>0) {
		 	c=(p[i]+p[j])/2;
		 	r=len(c-p[i]);
		 	for (int k=0;k<j;k++)
		 	 if (dcmp(len(p[k]-c)-r)>0) {
		 	 	c=center(p[i],p[j],p[k]);
		 	 	r=len(p[i]-c);
			  }
		 }
	}
	return r;
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("my.out","w",stdout);
	scanf("%d",&n);
	for (int i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
	printf("%.3lf\n",mincc());
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值