题目地址:poj2031
直接用最小生成树。
关于边权的计算,如果有重叠部分直接是0了
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstring>
const double eps=1e-8;
using namespace std;
int dcmp(double x) {return (x>eps)-(x<-eps);}
struct Point3
{
double x;
double y;
double z;
Point3(double x=0,double y=0,double z=0):x(x),y(y),z(z) {}
};
Point3 read_point3()
{
Point3 A;
scanf("%lf%lf%lf",&A.x,&A.y,&A.z);
return A;
}
Point3 operator-(Point3 A,Point3 B) {return Point3(A.x-B.x,A.y-B.y,A.z-B.z);}
typedef Point3 Vector3;
double Length(Point3 A)
{
return sqrt(A.x*A.x+A.y*A.y+A.z*A.z) ;
}
struct Sphere
{
Point3 c;
double r;
Sphere(Point3 c=Point3(0,0,0),double r=0):c(c),r(r) {}
};
struct edge
{
int u;
int v;
double w;
};
Sphere s[105];
edge e[10005];
int fa[10005];
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
bool edge_cmp(edge a,edge b)
{
return a.w<b.w;
}
int n,m;
int cc;
double kruskal()
{
double ans=0;
sort(e,e+m,edge_cmp);
for(int i=0;i<m;i++)
{
int x=find(e[i].u);
int y=find(e[i].v);
if(x!=y)
{
fa[x]=y;
ans+=e[i].w;
cc--;
}
}
return ans;
}
void init()
{
for(int i=0;i<n;i++)
{
fa[i]=i;
}
cc=n;
}
double calc_distance(Sphere A,Sphere B)
{
double d=Length(A.c-B.c);
double r1=A.r;
double r2=B.r;
if(dcmp(r1-r2)<0) swap(r1,r2);
if(dcmp(d-r1-r2)>=0) return d-r1-r2;
// else if(dcmp(d-(r1-r2))<=0) return r1-d-r2;
return 0;
}
int main()
{
while(cin>>n)
{
if(!n) break;
init();
for(int i=0;i<n;i++)
{
s[i].c=read_point3();
scanf("%lf",&s[i].r);
}
int cnt=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
e[cnt].u=i;
e[cnt].v=j;
e[cnt].w=calc_distance(s[i],s[j]);
cnt++;
}
m=cnt;
double ans=kruskal();
printf("%.3lf\n",ans);
}
}