题目大意
题目是说三维空间中有n个球,求这些球之间连接的最小距离。最小距离的意思就是他们球面边界的最小距离的和。并且球与球之间可能会有重复的部分,如果所有的球都重复的话,那么输出0.00,其余的输出最小距离和保留三位有效数字
分析
看似像是个数学题,实际上我们把三维空间拍扁,求的就是最小生成树。其中的权值w的计算公式为w=两个球心间的距离-球1的半径-球2的半径。这里需要注意如果两个球的权值有凹陷的话,权值直接设置为0.我之前的wa就是因为没有注意负数权值的情况。。。
题解(实际上感觉已经没有什么好说的了)
①输入数据
②计算权值
③克鲁斯卡尔
④输出答案
完整代码
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int f[11000],num[11000],to[11000],r[11000];
double cost[11000];
int bk[1100][1100];
int find(int k)
{
return f[k]==k?k:f[k]=find(f[k]);
}
bool cmp(int a,int b)
{
return cost[a]<cost[b];
}
struct node
{
double x,y,z,r;
}data[1000];
int main()
{
int n;
while(cin>>n&&n)
{
memset(bk,0,sizeof(bk));
double ans=0;
int p=0;
for(int i=0;i<n;i++)
cin>>data[i].x>>data[i].y>>data[i].z>>data[i].r;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i!=j&&!bk[i][j]&&!bk[j][i])
{
bk[i][j]=bk[j][i]=1;
num[p]=i;
to[p]=j;
double t=sqrt((data[i].x-data[j].x)*(data[i].x-data[j].x)+(data[i].y-data[j].y)*(data[i].y-data[j].y)+(data[i].z-data[j].z)*(data[i].z-data[j].z))-data[i].r-data[j].r;
cost[p++]=t>0?t:0;
}
for(int i=0;i<n;i++)
f[i]=i;
for(int i=0;i<p;i++)
r[i]=i;
sort(r,r+p,cmp);
for(int i=0;i<p;i++)
if(find(num[r[i]])!=find(to[r[i]]))
{
f[find(num[r[i]])]=find(to[r[i]]);
ans+=cost[r[i]];
}
printf("%.3f
",ans);
}
}