这题应该算最小生成树吧,怎么分类到几何了咧。。
给n个球的球心和半径,用长度最少的线,把这些球的表面连接起来。如果球相交,线的距离算成是0就行了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
struct T
{
double x;
double y;
double z;
double r;
};
struct edge
{
int u;
int v;
double w;
};
T cl[200];
edge e[11000];
double d[200][200];
double dis(T a,T 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;
}
int uset[200];
int root(int k)
{
if(k==uset[k])
return k;
return uset[k]=root(uset[k]);
}
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
int main()
{
int n,i,j,le,ra,rb;
double ans;
while (1)
{
scanf("%d",&n);
if (n == 0)
break;
for (i=0; i<n; i++)
{
scanf("%lf%lf%lf%lf",&cl[i].x,&cl[i].y,&cl[i].z,&cl[i].r);
}
le=0;
for (i=0; i<n; i++)
{
for (j=i+1; j<n; j++)
{
e[le].u=i;
e[le].v=j;
e[le].w=dis(cl[i],cl[j]);
e[le].w=e[le].w<0?0:e[le].w;
le++;
}
}
for (i=0; i<n; i++)
{
uset[i]=i;
}
sort(e,e+le,cmp);
ans=0;
for (i=0; i<le; i++)
{
ra=root(e[i].u);
rb=root(e[i].v);
if (ra != rb)
{
ans+=e[i].w;
uset[ra]=rb;
n--;
}
}
printf("%.3f\n",ans);
}
}