【bzoj 1336&&1337&&2823】 最小圆覆盖

Description

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

这道题先对点随机化处理,设前i个点的最小圆覆盖为C_i,若当前要加入的点p_i不在C_{i-1}内则p_i一定在C_i的边界上,然后在1~i-1中枚举j,若p_j不在圆内,就以p_ip_j为直径构成圆,再在1~j-1中枚举k,用p_ip_jp_k三点构成新圆即可,下面是程序(注意三题的输出格式不同):

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<iostream>
using namespace std;
const int N=100005;
const double eps=1e-10;
struct Point{
	double x,y;
	Point operator +(const Point &p)const{
		return (Point){x+p.x,y+p.y};
	}
	Point operator /(const double p)const{
		return (Point){x/p,y/p};
	}
}p[N],o,t1,t2;
int n;
double r;
double L(Point &a,Point &b){
	double x=a.x-b.x,y=a.y-b.y;
	return x*x+y*y;
}
void makec(Point &a,Point &b,Point &c){
	double a1,a2,b1,b2,c1,c2;
	a1=2*(b.x-a.x);
	b1=2*(b.y-a.y);
	c1=(b.x+a.x)*(b.x-a.x)+(b.y+a.y)*(b.y-a.y);
	a2=2*(c.x-b.x);
	b2=2*(c.y-b.y);
	c2=(c.x+b.x)*(c.x-b.x)+(c.y+b.y)*(c.y-b.y);
	o.x=(c1*b2-c2*b1)/(a1*b2-a2*b1);
	o.y=(a1*c2-a2*c1)/(a1*b2-a2*b1);
	r=L(o,a);
}
inline bool in(Point &p){
	return r-L(p,o)>=-eps;
}
int main(){
	srand(9837528);
	int i,j,k;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%lf%lf",&p[i].x,&p[i].y);
	}
	random_shuffle(p+1,p+n+1);
	makec(p[1],p[2],p[3]);
	for(i=4;i<=n;i++){
		if(in(p[i])){
			continue;
		}
		o=p[i],r=0;
		for(j=1;j<i;j++){
			if(in(p[j])){
				continue;
			}
			o=(p[i]+p[j])/2;
			r=L(p[i],o);
			for(k=1;k<j;k++){
				if(in(p[k])){
					continue;
				}
				makec(p[i],p[j],p[k]);
			}
		}
	}
	printf("%.10lf\n%.10lf %.10lf",sqrt(r),o.x,o.y);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值