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

本文探讨了在空间站建设中,如何通过算法优化单元间的连接,确保所有单元可通过走廊相连,同时最小化走廊总长度。采用Prim算法计算最小生成树,实现单元间连接的最优化。

题:
您是空间站工程团队的成员,在空间站的建造过程中被分配了一项任务。您需要编写一个计算机程序来完成该任务。

空间站由许多单元组成,称为单元。所有的细胞都是球形的,但它们的大小不一定是一致的。在空间站成功进入轨道后不久,每个单元就固定在预定位置。奇怪的是,两个细胞可能相互接触,甚至可能重叠。在极端情况下,一个单元可能完全封闭另一个单元。我不知道这样的安排是怎么可能的。

所有的单元都必须连接起来,因为机组成员应该能够从任何一个单元走到任何其他单元。如果(1)A和B彼此接触或重叠,(2)A和B通过“走廊”连接,或者(3)有一个C单元,这样从A到C以及从B到C都可以从A单元步行到另一个B单元。请注意,条件(3)应进行传递性解释。
您需要设计一个配置,即哪对单元将与走廊连接。在走廊配置中有一些自由。例如,如果有三个单元格A、B和C,彼此不接触或不重叠,则至少可以有三个计划来连接所有三个单元格。第一个是修建A-B和A-C走廊,第二个是B-C和B-A走廊,第三个是C-A和C-B走廊。修建走廊的成本与其长度成正比。因此,应选择走廊总长度最短的平面图。
可以忽略走廊的宽度。在两个单元表面上的点之间建立一条走廊。它可以任意长,但当然要选最短的。即使两条走廊A-B和C-D在空间上相交,也不认为它们在(例如)A和C之间形成连接路径。换句话说,您可能认为两条走廊从未相交。
输入
输入由多个数据集组成。每个数据集的格式如下。
N号
x1 y1 z1 r1型
x2 Y2 Z2 R2型

……
Xn-yn-zn-rn型
数据集的第一行包含整数n,即单元格数。n为正,不超过100。
以下n行是对单元格的描述。一条直线上的四个值是圆心的x、y和z坐标,以及球体的半径(问题的其余部分称为r),顺序如下。每个值都由一个小数点给出,小数点后有3位数字。值由空格字符分隔。
x、y、z和r中的每一个都是正的,小于100.0。
输入的结尾由包含零的行指示。

输出
对于每个数据集,应打印走廊的最短总长度,每一条都单独打印。打印的值应在小数点后3位。误差不得大于0.001。

请注意,如果不需要走廊,也就是说,如果所有单元都没有走廊连接,则走廊的最短总长度为0.000。
题解:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include <iostream>
#include <stack>
using namespace std;
#define MaxInt 0x3f3f3f3f
#define N 110
//创建map二维数组储存图表,low数组记录每2个点间最小权值,visited数组标记某点是否已访问
double map1[N][N],low[N],visited[N];
int n,pos=1;
int w=0;
double prim()
{
    int i,j,pos;
    double min1,result=0;
    memset(visited,0,sizeof(visited));
//从某点开始,分别标记和记录该点
    visited[1]=1;
    pos=1;
//第一次给low数组赋值
    for(i=1; i<=n; i++)
        //if(i!=pos)
        low[i]=map1[pos][i];
//再运行n-1次
    for(i=1; i<n; i++)
    {
//找出最小权值并记录位置
        min1=MaxInt;
        for(j=1; j<=n; j++)
            if(visited[j]==0&&min1>low[j])
            {
                min1=low[j];
                pos=j;
            }
//最小权值累加
        result+=low[pos];
//标记该点
        visited[pos]=1;
//更新权值
        for(j=1; j<=n; j++)
            if(visited[j]==0&&low[j]>map1[pos][j])
                low[j]=map1[pos][j];
    }
   return result;
}

int main()
{
    double x[909],y[909],z[909],r[909],d=0;
    int i,j,F;
    double ans;
    int t;
    double v[9999],re=0;
    memset(v,0,sizeof(v));
    while(scanf("%d",&n)&&n)
    {
//所有权值初始化为最大
        t=1;
        F=n;
        for(i=1; i<=n; i++)
            for(j=1; j<=n; j++)
            {
                if(i==j)
                    map1[i][j]=0;
                else
                    map1[i][j]=MaxInt;
            }

        //cout<<w<<endl;
         for(i=1; i<=n; i++)
        {
            scanf("%lf%lf%lf%lf",&x[i],&y[i],&z[i],&r[i]);
        }
        for(i=1; i<=n; i++)
        {
            //scanf("%lf%lf%lf%lf",&x[i],&y[i],&z[i],&r[i]);

            //cout<<v[i]<<endl;
            for(j=1+i; j<=n; j++)
            {

                d=(double)sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]));
                d=d-r[i]-r[j];
                if(d<=0)
                    d=0;
                map1[i][j]=map1[j][i]=d;
            }


        }
         re=prim();
         printf("%.3lf\n",re);

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值