题意:
就是给出三维坐标系上的一些球的球心坐标和其半径,搭建通路,使得他们能够相互连通。如果两个球有重叠的部分则算为已连通,无需再搭桥。求搭建通路的最小费用
还是最小生成树。。
#include<iostream>
#include<cmath>
#include<iomanip>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define eps 1e-10
#define inf 10000.0
using namespace std;
int father[10009];
struct point
{
double x,y,z;
double r;
};
int EPS(double k)
{
if(fabs(k)<eps)
return 0;
return k>0?1:-1;
}
double dist(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;
}
struct cadongllas
{
int x, y;
double value;
}edge[10009];
bool cmp (cadongllas x, cadongllas y)
{
return EPS (x.value - y.value) < 0;
}
int get_father (int x)
{
if (father[x] == x)
return x;
return get_father (father[x]);
}
int main(int i,int j)
{
int n;
while(cin>>n)
{
int cnt = 0;
if(n<=0)
break;
point* node=new point[n+1];
double w[101][101];
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
w[i][j]=inf;
/*Input*/
for(i=1;i<=n;i++)
cin>>node[i].x>>node[i].y>>node[i].z>>node[i].r;
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++)
{
double temp=dist(node[i],node[j]);
if(EPS(temp)<=0)
w[i][j]=w[j][i]=0; //两个球接触(相交),则距离(权值)为0
else
w[i][j]=w[j][i]=temp;
}
double sum_w=0.0;
/*Prim Algorithm*/
/*bool vist[101]={false};
int s=1;
vist[s]=true;
int fi;
for(int count=1;count<n;count++)
{
double min=inf;
for(i=2;i<=n;i++)
if(!vist[i])
if(min>w[s][i])
{
min=w[s][i];
fi=i;
}
sum_w+=w[s][fi];
vist[fi]=true;
for(i=2;i<=n;i++) //新源点s'继承最新合并进来的fi的性质
if(!vist[i]) //以fi到其他点的更短路 取代旧源点s到其他点的权值
if(w[s][i]>w[fi][i])
w[s][i]=w[fi][i];
}*/
rep (i, 1, n)
father[i] = i;
rep (i, 1, n)
rep (j, i + 1, n)
edge[++cnt] = (cadongllas){i, j, w[i][j]};
sort (edge + 1, edge + 1 + cnt, cmp);
rep (i, 1, cnt)
{
int u = get_father (edge[i].x), v = get_father (edge[i].y);
if (u != v)
father[u] = v, sum_w += edge[i].value;
}
cout<<fixed<<setprecision(3)<<sum_w<<endl;
delete node;
}
return 0;
}