版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hxxjxw/article/details/84203973
题目大意:
宇宙中有n个城市,需要建一个指挥部,使得指挥部与所有城市之间的距离尽可能小。问指挥部和最远城市之间的最小欧几里得距离是多少。
题解:
就是让球这n个点的最小球覆盖,指挥部是圆心,球的半径就是指挥部到最远城市之间的欧几里得距离
红书上有板子,直接套就可以过了
这么长的两页板子经常会漏掉一些,所以一定敲完之后查下错,不然敲完之后WA可还可能觉得是套板子不对......
注意定义Tpoint的xyz类型应该用double,而不是int!!!
#include<bits/stdc++.h>
#include<cstring>
#define ll long long
#define INF 1000000007
#define eps 1e-6
#define mod 1000000007
#define double long double
using namespace std;
struct Tpoint
{
double x,y,z;
};
int npoint,nouter;
Tpoint pt[200000],outer[4],res;
double radius,tmp;
inline double dist(Tpoint p1,Tpoint p2)
{
double dx=p1.x-p2.x,dy=p1.y-p2.y,dz=p1.z-p2.z;
return (dx*dx+dy*dy+dz*dz);
}
inline double dot(Tpoint p1,Tpoint p2)
{
return p1.x*p2.x+p1.y*p2.y+p1.z*p2.z;
}
void ball()
{
Tpoint q[3];
double m[3][3],sol[3],L[3],det;
int i,j;
res.x=res.y=res.z=radius=0;
switch(nouter)
{
case 1:
res=outer[0];
break;
case 2:
res.x=(outer[0].x+outer[1].x)/2;
res.y=(outer[0].y+outer[1].y)/2;
res.z=(outer[0].z+outer[1].z)/2;
radius=dist(res,outer[0]);
break;
case 3:
for(int i=0; i<2; ++i)
{
q[i].x=outer[i+1].x-outer[0].x;
q[i].y=outer[i+1].y-outer[0].y;
q[i].z=outer[i+1].z-outer[0].z;
}
for(int i=0; i<2; ++i)
for(int j=0; j<2; ++j)
m[i][j]=dot(q[i],q[j])*2;
for(int i=0; i<2; ++i)
sol[i]=dot(q[i],q[i]);
if(fabs(det=m[0][0]*m[1][1]-m[0][1]*m[1][0])<eps)
return;
L[0]=(sol[0]*m[1][1]-sol[1]*m[0][1])/det;
L[1]=(sol[1]*m[0][0]-sol[0]*m[1][0])/det;
res.x=outer[0].x+q[0].x*L[0]+q[1].x*L[1];
res.y=outer[0].y+q[0].y*L[0]+q[1].y*L[1];
res.z=outer[0].z+q[0].z*L[0]+q[1].z*L[1];
radius=dist(res,outer[0]);
break;
case 4:
for(int i=0; i<3; ++i)
{
q[i].x=outer[i+1].x-outer[0].x;
q[i].y=outer[i+1].y-outer[0].y;
q[i].z=outer[i+1].z-outer[0].z;
sol[i]=dot(q[i],q[i]);
}
for(int i=0; i<3; ++i)
for(int j=0; j<3; ++j)
m[i][j]=dot(q[i],q[j])*2;
det=m[0][0]*m[1][1]*m[2][2]
+m[0][1]*m[1][2]*m[2][0]
+m[0][2]*m[2][1]*m[1][0]
-m[0][2]*m[1][1]*m[2][0]
-m[0][1]*m[1][0]*m[2][2]
-m[0][0]*m[1][2]*m[2][1];
if(fabs(det)<eps)return ;
for(int j=0; j<3; ++j)
{
for(int i=0; i<3; ++i)
m[i][j]=sol[i];
L[j]=(m[0][0]*m[1][1]*m[2][2]
+m[0][1]*m[1][2]*m[2][0]
+m[0][2]*m[2][1]*m[1][0]
-m[0][2]*m[1][1]*m[2][0]
-m[0][1]*m[1][0]*m[2][2]
-m[0][0]*m[1][2]*m[2][1]
)/det;
for(int i=0; i<3; ++i)
m[i][j]=dot(q[i],q[j])*2;
}
res=outer[0];
for(int i=0; i<3; ++i)
{
res.x+=q[i].x*L[i];
res.y+=q[i].y*L[i];
res.z+=q[i].z*L[i];
}
radius=dist(res,outer[0]);
}
}
void minball(int n)
{
ball();
if(nouter<4)
{
for(int i=0; i<n; ++i)
if(dist(res,pt[i])-radius>eps)
{
outer[nouter]=pt[i];
++nouter;
minball(i);
--nouter;
if(i>0)
{
Tpoint Tt=pt[i];
memmove(&pt[1],&pt[0],sizeof(Tpoint)*i);
pt[0]=Tt;
}
}
}
}
double smallest_ball()
{
radius=-1;
for(int i=0; i<npoint; ++i)
{
if(dist(res,pt[i])-radius>eps)
{
nouter=1;
outer[0]=pt[i];
minball(i);
}
}
return sqrt(radius);
}
int main()
{
//freopen("input.txt","r",stdin);
while(cin>>npoint)
{
for(int i=0; i<npoint; ++i)
{
cin>>pt[i].x>>pt[i].y>>pt[i].z;
}
cout<<fixed<<setprecision(15)<<smallest_ball()<<endl;
}
return 0;
}
/*
3
0 0 0
3 0 0
0 4 0
4
0 0 0
1 0 0
0 1 0
0 0 1
*/