题目大意:
给出n个三维空间的球体,球体是以圆心坐标+半径来表示的,要求在球面上建桥使所有的球联通,求联通所建桥的最小长度。
解题思路:
刚开始看到三维的有一点蒙,不过精心想了想还是很容易的。
1、两个球之间要在球面上建的通路的长度是两球圆心之间的距离减去两球半径。
2、当所建通路的长度小于EPS时,就认为它两个已经联通,距离为0。
3、自己和自己之间是不可达的。
4、最小长度可以用最小生成树算法完成,我在这里用的prim算法。
下面是代码 :
#include <stdio.h>
#include <math.h>
struct node
{
double x,y,z,r;
} point[110];
double map1[110][110];
const double inf=100000.0;
const double eps=1e-10;
double dist(node A,node B)
{
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z))-A.r-B.r;
}
double prim(int n)
{
double dis[110],ret=0;
int v[110],i,j,k;
for (i=0; i<n; i++)
dis[i]=inf,v[i]=0;
for (dis[j=0]=0; j<n; j++)
{
for (k=-1,i=0; i<n; i++)
if (!v[i]&&(k==-1||dis[i]<dis[k]))
k=i;
for (v[k]=1,ret+=dis[k],i=0; i<n; i++)
if (!v[i]&&map1[k][i]<dis[i])
dis[i]=map1[k][i];
}
return ret;
}
int main()
{
int n,i,j;
while(scanf("%d",&n),n)
{
for(i=0; i<n; i++)
{
scanf("%lf%lf%lf%lf",&point[i].x,&point[i].y,&point[i].z,&point[i].r);
}
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
if(j==i)
{
map1[i][i]=inf;
continue;
}
map1[i][j]=dist(point[i],point[j]);
if(map1[i][j]<eps)map1[i][j]=0;
}
}
printf("%.3f\n",prim(n));
}
return 0;
}