POJ 2031 Building a Space Station(最小生成树)

题目大意

题目是说三维空间中有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\n",ans);
  }
}
posted @ 2018-11-23 16:54  baccano!  阅读(178)  评论(0编辑  收藏  举报