1. 程式人生 > >【bzoj 1336&&1337&&2823】 最小圓覆蓋

【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;
}