洛谷P1742 最小圆覆盖

题目描述

给出N个点,让你画一个最小的包含所有点的圆。

输入输出格式

输入格式:

 

先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000.0)

 

输出格式:

 

输出圆的半径,及圆心的坐标,保留10位小数

 

输入输出样例

输入样例#1: 复制

6
8.0 9.0
4.0 7.5
1.0 2.0
5.1 8.7
9.0 2.0
4.5 1.0

输出样例#1: 复制

5.0000000000
5.0000000000 5.0000000000

说明

5.00 5.00 5.0


模拟,就是三点确定一个圆,然后判断剩下的点是不是在圆内,不是的话找三个圆外的点,构成一个新的圆,这个新的圆一定会比原来的圆大,注意找的时候不是一下找三个点,因为我们要求的是最小的圆,找到第一个点的时候,直接把原来的圆的半径扩大到这个点,第二个也是,但是第三个需要特判一下,因为如果直接把半径扩大到第三个点的话,就有可能直接把上面两个点直接包含了,而我们要求的是最小的圆,所以最后一次找到这个三个点时,直接三点定圆,就一定会包含所有的点

#include<bits/stdc++.h> 
using namespace std;
struct circle {double x,y,r;};
struct point {double x,y;};
point poi[100005];
int n;
double dis(point a,point b)//计算两点之间的距离函数 
{
	return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}
circle turn(point a,point b,point c)//三点确定一个圆 
{
	circle cl;
	double A,B,C,D,E,F,x0,y0,r0;
	A=b.x-a.x; B=b.y-a.y;
	C=c.x-a.x; D=c.y-a.y;
	E=( (b.x*b.x-a.x*a.x) + (b.y*b.y-a.y*a.y) )/2;
	F=( (c.x*c.x-a.x*a.x) + (c.y*c.y-a.y*a.y) )/2;
	
	x0=-(D*E-B*F)/(B*C-A*D);
	y0=-(A*F-C*E)/(B*C-A*D);
	r0=sqrt( (a.x-x0)*(a.x-x0) + (a.y-y0)*(a.y-y0) );
	cl.x=x0; cl.y=y0; cl.r=r0; 
	return cl;
}
point midpoint(point a,point b)//计算中点 
{
	point t={.x=(a.x+b.x)/2,.y=(a.y+b.y)/2};
	return t;
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++) 
	cin>>poi[i].x>>poi[i].y;
	
	random_shuffle(poi,poi+n);//随机化
	
	circle ans;
	point temp=poi[0];
	double R=0.0;
	
	for(int i=1;i<n;i++)
	if(dis(temp,poi[i])>R)
	{
		temp=midpoint(poi[0],poi[i]); 
		R=dis(poi[i],temp);
		
		for(int j=1;j<i;j++)
		if(dis(temp,poi[j])>R)
		{
			temp=midpoint(poi[j],poi[i]); 
			R=dis(poi[i],temp);
			
			for(int k=0;k<j;k++)
			if(dis(temp,poi[k])>R)
			{
				ans=turn(poi[i],poi[j],poi[k]);
				temp=(point){.x=ans.x, .y=ans.y};
				R=dis(poi[i],temp);
			}
		}
	}
	printf("%.10lf\n%.10lf %.10lf\n",R,temp.x,temp.y);
	return 0;
}








 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值