题目传送门:POJ - 2031 Building a Space Station
题目大意:
给你n个球体,输入n,接下俩输入n行中每行有四个数,分别代表球的球心坐标x,y,z 和球径r 。
可以在两球之间建立通道,现在要将所有球体联通,求最小代价。
分析:
可以知道任意两个球都可以建立通道,因此我们构建一张图,里面是所有球的所有通道,然后在跑prim就可以了
通道的大小是(球心距-两个球的半径) 即 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;(a,b表示两个球)
若该值小于等于0,则距离设置为0,因为他们重合或者相切可以直接到达距离为0。
代码:prim
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> using namespace std; const int MAX=200; const int INF=0x3f3f3f3f; int n; double x,y,z,r; //记得这些都要double double map[MAX][MAX]; double dist[MAX]; bool vis[MAX]; struct point //结构体存储球的坐标和半径 { double x,y,z,r; point(){} point(double a,double b,double c,double d) { x=a,y=b,z=c,r=d; } }po[MAX]; double dis(point a,point b) //计算两个球之间的距离 名字取distance会编译错误QAQ {double ans=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; if(ans<=0)return 0; else return ans; } double prim() { for(int i=0;i<n;i++) { dist[i]=INF; vis[i]=false; } dist[0]=0; double min,ans=0; int pos; for(int i=0;i<n;i++) { min=INF; for(int j=0;j<n;j++) { if(!vis[j]&&dist[j]<min) { min=dist[j]; pos=j; } } vis[pos]=true; ans+=min; for(int j=0;j<n;j++) { if(!vis[j]&&dist[j]>map[pos][j]) dist[j]=map[pos][j]; } } return ans; } int main() { while(cin>>n&&n) { memset(po,0,sizeof(po)); memset(map,0,sizeof(map)); for(int i=0;i<n;i++) { cin>>x>>y>>z>>r; po[i]=point(x,y,z,r); } for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) map[i][j]=map[j][i]=dis(po[i],po[j]); double ans=prim(); printf("%.3lf ",ans); } return 0; }