poj 2031

可可愛愛沒有鬧呆發表於2020-10-16

每日一題 9.28.2020
題意:
就是給出三維座標系上的一些球的球心座標和其半徑,搭建通路,使得他們能夠相互連通。如果兩個球有重疊的部分則算為已連通,無需再搭橋。求搭建通路的最小費用(費用就是邊權,就是兩個球面之間的距離)。
解題思路:
邊權 = AB球面距離 = A球心到B球心的距離 – A球半徑 – B球半徑

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include<math.h>
using namespace std;
struct cir
{
    double x,y,z,r;
}p[111];
struct node
{
    int u;
    int v;
    double w;
}r[10010];
int f[111];
double dis (cir a, cir b) {
    double xx = a.x-b.x, yy = a.y-b.y, zz = a.z-b.z;
    double d = sqrt (xx*xx + yy*yy + zz*zz);
    if (d <= a.r+b.r)
        return 0;
    return d - a.r - b.r;
}

bool cmp(node a,node b)
{
  return a.w<b.w;

}
int Find(int x)
{
    if(f[x]!=x)
        Find(f[x]);
    else return x;
}
int join(int x,int y)
{
   int rot1=Find(x);
    int rot2=Find(y);
    if(rot1!=rot2)
    {
        f[rot1]=rot2;
        return 1;
    }
    return 0;
}
int main()
{
    int n;
    while(cin>>n&&n)
    {

            for(int i=1;i<=n;i++)
            {
                cin>>p[i].x>>p[i].y>>p[i].z>>p[i].r;
                f[i]=i;
            }
            int len=0;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<i;j++)
                {
                   r[len].u=i;
                   r[len].v=j;
                   r[len++].w=dis(p[i],p[j]);

                }
            }
            sort(r,r+len,cmp);
            double num=0.0;int coun=0;
            for(int i=0;i<len;i++)
            {
                if(join(r[i].u,r[i].v))
                {
                    num+=r[i].w;
                    coun++;
                }
                if(coun==n-1) break;
            }
            printf("%.3f\n",num);
        }

}