题目不难,大致题意为:给定n个球中心的三维坐标,及半径。这些球中可能有相交的,也可能有相切的,也可能有相离。现要是的每个球都是相连的,相求相连的条件就是:
1)相切或相交
2)A->B,B->C则A->C即相连具有传递性和相互性(A->B<==>B->A)
3)A与B相离,在它们之间连一条线,注意线的长度为表面的连线长度。
对于相离的球,要求我们在它们之间连线,使得所有的球都是相连的,并求出所有连线的最小长度。
说白了,就是最小生成树算法。
但要注意几点:
1)相切或相连的球之间的距离为0
2)相离的球之间的距离为两球心的距离-两球的半径
3)注意精度问题,因为涉及到浮点数运算。那么判0问题要另设函数
然后就是kruskal算法或prim算法了。
下面是代码: 248K+16MS
#include<stdio.h>
#include<stdlib.h> //sort
#include<string.h>
#include<math.h> // sqrt
#include<algorithm> //qsort
#define Max 110
#define eps 1e-10 //最低精度
using namespace std;
struct Node{ // 记录距离
int from;
int to;
double value;
}node[Max*Max];
struct Point{ // 记录球坐标及半径
double x;
double y;
double z;
double r;
}point[Max];
int set[Max];
int n;
bool cmp(Node p,Node q){ // sort 的 cmp 函数
return p.value<q.value;
}
/*int cmp(const void *p,const void *q){ // qsort 的 cmp 函数 ,比较了一下,sort要快的多,毕竟qsort是c++标准函数库中的模板函数
return (((Node*)p)->value>((Node*)q)->value)?1:-1; // 注意 qsort 与 sort 的cmp不同之处,前者为int,>0则排序,否则不排序,而后者为bool,true不排序,false排序
}*/
int find(int x){ // 查父节点
int a=x,j;
while(set[x]!=x)
x=set[x];
j=x;
while(a!=j){ // 路径压缩
int temp=set[a];
set[a]=j;
a=temp;
}
return x;
}
double Get_dis(Point a,Point 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 EPS(double x){ // 判0 函数
if(fabs(x)<eps) // 将-eps——eps范围设置为‘0’,
return 0;
else if(x<0) //小于0
return -1;
else //大于0
return 1;
}
int main(){
while(scanf("%d",&n),n){
int i,j;
for(i=1;i<=n;i++)
scanf("%lf%lf%lf%lf",&point[i].x,&point[i].y,&point[i].z,&point[i].r); // 输入顶点
int pivot=0;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++){
node[pivot].from=i,node[pivot].to=j;
double temp=Get_dis(point[i],point[j]);
if(EPS(temp)<=0) // 若小于或等于0,则距离为0
node[pivot++].value=0.0;
else //若大于0
node[pivot++].value=temp;
}
for(i=1;i<=n;i++)
set[i]=i;
//qsort(node,pivot,sizeof(Node),cmp);
sort(node,node+pivot,cmp); // 按距离从小到大排序
double Sum=0.0; // 总长度
for(i=0;i<pivot;i++){
int x=find(node[i].from); //查父节点
int y=find(node[i].to);
if(x!=y){ // 并父节点,大并小
Sum+=node[i].value; // 增加这条边,长度相应增加
if(x>y)
set[x]=y;
else
set[y]=x;
}
}
printf("%.3lf\n",Sum); // 输出最小生成树长度
}
return 0;
}