叮叮~
萌新一枚呀
笔记仅供参考,具体还是要以上课讲授的内容为准
另外
左老师YYDS
题面
描述
给出平面上N(N <=10^5)个点。请求出一个半径最小的圆覆盖住所有的点。输入
第一行给出数字N,接下来N行,每行两个实数x,y表示其坐标。
其中,-100000<=x,y<=100000
输出
第一行输出最小覆盖圆的圆心
第二行输出半径
输出保留三位小数.
测试数据
Case#1:
Input
4
1 0
0 1
0 -1
-1 0
Output
0.000 0.000
1.000
另外附上一组本人程序跑出来的测试数据
(有的小伙伴跑出来nan 这时候可以去提交混15分 嗨嗨嗨)
Case#2:
Input
20
0 0
1 5
2 6
-1 3
4 6
2 8
5 4
3 9
7 7
5 9
2 3
3 5
1 2
3 0
-2 -3
-3 -5
-6 -9
-1 -3
-5 -6
-7 -1
output
-0.500 0.000
10.548
Case#3:
Input
5
-0.5 0
0.5 0
0 0.866
-0.25 0.217
0.3 0.207
Output
-0.000 0.289
0.577
题解
在计算机中表示点常用点对,表示直线常用点和方向向量,以此来在程序中表述
但是本题由于实在是没思路,所以就没用
这里没使用随机分布的方法来简化最小覆盖圆的计算的时间复杂度
这里只给出一种办法
大概步骤:
第一层循环 枚举第一个点
第二层循环 枚举第二个点
判断第二个点和圆的关系
这时构造两点共圆
两点不能确定圆
但是我们可以知道,以这两点作为直径的时候,圆是最小的
因此如此做圆
第三层循环 枚举第三个点
判断是不是在圆上or圆内
然后选择是不是构造三点出圆
每次都会判断是否进行了覆盖 恰好完全覆盖时则会最小
可以用随机函数,将点的分布随机化,这样得到最小覆盖圆的速度其实会更快,时间复杂度接近O(n)而不是严格的O(n^3)
因此本题关键在于求 两点求出的圆心和半径 以及 三点求出的圆心和半径
这是输入三个点求横纵坐标的两个函数
用到了行列式进行推导
最终获得的化简结果
返回值即使横坐标与纵坐标
输入时,采用a[] b[]两个数组分别存储横纵坐标=-=
double solve3xpoints(double x1,double y1,double x2,double y2,double x3,double y3){
double a=x1-x2;
double b=y1-y2;
double c=x1-x3;
double d=y1-y3;
double e=((x1*x1-x2*x2)-(y2*y2-y1*y1))/2;
double f=((x1*x1-x3*x3)-(y3*y3-y1*y1))/2;
return -(d*e-b*f)/(b*c-a*d);
}
double solve3ypoints(double x1,double y1,double x2,double y2,double x3,double y3){
double a=x1-x2;
double b=y1-y2;
double c=x1-x3;
double d=y1-y3;
double e=((x1*x1-x2*x2)-(y2*y2-y1*y1))/2;
double f=((x1*x1-x3*x3)-(y3*y3-y1*y1))/2;
return -(a*f-c*e)/(b*c-a*d);
}
下面这个是比较浮点数的常用方法
因为会有精度问题
所以经常采用下列方法比较
int cmpd(double a,double b){
if(fabs(a-b)<1e-8)
return 0;
if(a<b)
return -1;
return 1;
}
下面是两点确定圆心横纵坐标的代码
double solvex2points(double x1,double x2){
return (x1+x2)/2;
}
double solvey2points(double y1,double y2){
return (y1+y2)/2;
}
下面是求两点距离
double solve2pointsdis(double x1,double y1,double x2,double y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
用结构体储存最后的圆(好看)
AC代码
#include<iostream>
#include<math.h>
using namespace std;
const int N=100001;
double a[N],b[N];
struct Circle{
double x;
double y;
double r;
};
double solvex2points(double x1,double x2){
return (x1+x2)/2;
}
double solvey2points(double y1,double y2){
return (y1+y2)/2;
}
double solve2pointsdis(double x1,double y1,double x2,double y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int cmpd(double a,double b){
if(fabs(a-b)<1e-8)
return 0;
if(a<b)
return -1;
return 1;
}
double solve3xpoints(double x1,double y1,double x2,double y2,double x3,double y3){
double a=x1-x2;
double b=y1-y2;
double c=x1-x3;
double d=y1-y3;
double e=((x1*x1-x2*x2)-(y2*y2-y1*y1))/2;
double f=((x1*x1-x3*x3)-(y3*y3-y1*y1))/2;
return -(d*e-b*f)/(b*c-a*d);
}
double solve3ypoints(double x1,double y1,double x2,double y2,double x3,double y3){
double a=x1-x2;
double b=y1-y2;
double c=x1-x3;
double d=y1-y3;
double e=((x1*x1-x2*x2)-(y2*y2-y1*y1))/2;
double f=((x1*x1-x3*x3)-(y3*y3-y1*y1))/2;
return -(a*f-c*e)/(b*c-a*d);
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i]>>b[i];
}//Read
Circle cir;
cir.x=a[0];
cir.y=b[0];
cir.r=0;
//Circle
for(int i = 0;i < n;i++)
{
if(cmpd(cir.r,solve2pointsdis(cir.x,cir.y,a[i],b[i]) )== -1)
{
cir.x=a[i];
cir.y=b[i];
for(int j = 0;j < i;j++)
{
if(cmpd(cir.r,solve2pointsdis(cir.x,cir.y,a[j],b[j]) )== -1)
{
cir.x=solvex2points(a[i],a[j]);
cir.y=solvey2points(b[i],b[j]);
cir.r=(solve2pointsdis(a[i],b[i],a[j],b[j]))/2;
for(int k = 0;k < j;k++)
{
if(cmpd(cir.r,solve2pointsdis(cir.x,cir.y,a[k],b[k])) == -1){
cir.x=solve3xpoints(a[i],b[i],a[j],b[j],a[k],b[k]);
cir.y=solve3ypoints(a[i],b[i],a[j],b[j],a[k],b[k]);
cir.r=solve2pointsdis(a[i],b[i],cir.x,cir.y);
}
}
}
}
}
}
printf("%.3lf %.3lf\n",cir.x,cir.y);
printf("%.3lf",cir.r);
}
周末愉快!