Building a Space Station -POj 2031(最小生成树 详解注释)

题目链接
给定N个三维圆心及其半径(x,y,z,r);求连通它们的最小生成树。两个球若相交视为连通。 N<101,坐标非负且小于100.000。
Input
多组输入,以0结束。
Output
最短连通距离,三位小数。
Sample Input
3
10.000 10.000 50.000 10.000
40.000 10.000 50.000 10.000
40.000 40.000 50.000 10.000
2
30.000 30.000 30.000 20.000
40.000 40.000 40.000 20.000
5
5.729 15.143 3.996 25.837
6.013 14.372 4.818 10.671
80.115 63.292 84.477 15.120
64.095 80.924 70.029 14.881
39.472 85.116 71.369 5.553
0
Sample Output
20.000
0.000
73.834

题意思路:
若2个圆心之间的距离小于等于2个半径之和代表2个圆连通,那么可以认为边权是0.
若不连通边权为 距离-半径之和。
最后求出让所有圆连通的最小的距离(最小生成树)

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=105;
const int inf=0x3f3f3f3f;
struct C
{
    double x,y,z,r;
} c[maxn];
int n;
double mp[maxn][maxn],dis[maxn];
bool vis[maxn];
double prime()
{
    double ans=0;
    for(int i=1;i<=n;i++)
    {
        dis[i]=inf;
    }
    memset(vis,false,sizeof(vis));
    for(int i=0;i<n;i++)//加入n个点,遍历n次
    {
        int v=-1;
        for(int j=1;j<=n;j++)//Prime算法的核心,遍历所有未加入集合Vnew的点,
        {
            if(!vis[j]&&(v==-1||dis[v]>dis[j]))//如果该点未加入Vnew,且该点距离i(u)点较近,则
                v=j;//更新v点,     直到找到一条距离Vnew中的点u最近的一条边u-v
        }
        vis[v]=true;//将v点加入点集合Vnew,相当于将<u,v>边加入边集合Enew中
        //for(int j=1;j<=n;j++)
        if(i!=0)//if(i)等价于if(i!=0),if(!i)等价于if(i==0) //在C语言中0为假,非0为真
            ans+=dis[v];// 不是第一个点的话 加上距离
        for(int j=1;j<=n;j++)
        {
           //if(!vis[j]&&dis[j]>mp[v][j])
             //   dis[j]=mp[v][j];// 更新点集合Vnew到其他点的距离    ,直到Vnew=V
              dis[j]=min(dis[j],mp[v][j]);
        }
    }
    return ans;
}
int main()
{
    while(cin>>n&&n!=0)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                mp[i][j]=inf;
            }
        }
        for(int i=1;i<=n;i++)
        {
            cin>>c[i].x>>c[i].y>>c[i].z>>c[i].r;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                double x=c[i].x-c[j].x;
                double y=c[i].y-c[j].y;
                double z=c[i].z-c[j].z;
                double r=c[i].r+c[j].r;
                double d=sqrt(x*x+y*y+z*z);
                if(d>r)
                {
                    mp[i][j]=mp[j][i]=min(mp[i][j],d-r);
                }
                else
                {
                    mp[i][j]=mp[j][i]=0;
                }
            }
        }
        printf("%.3lf\n",prime());//printf输出float和double都可以用%f,double还可以用%lf
        //scanf输入float用%f,double输入用%lf,不能混用
    }
    return 0;
}

收获感悟:当你真的理解并熟悉一个算法后,代码行看起来就不是那么难以理解了,当一个相关的算法理解后,还有些看不懂代码时可能就是语法知识点有些还不知道,百度查一下就可以了。然后要做的就是下次再遇到类似的题目时,熟练的把它敲出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值