Building a Space Station (Kruskal算法)

题意:有n个space station,每个space station都是一个球体,已知球的坐标,半径,(x,y,z,r都是double型的)现在要求在space station之间建个通道让所有space station都连接起来,求最小需要建立的通道;注意:如果两个space station相接触或相交就不需要建立通道,即通道为0;很明显求最小生成树;

space station间的距离:(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)-r1-r2;

这次用Kruskal算法,需要用到并查集;

下面是代码:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
const int M=105;            //最多100个space station;
int uset[M];                //uset数组存该点的祖先;
int n, cnt;                 //n是space station的个数;cnt表示边的条数;
struct cell{                //struct cell中是space station的坐标和半径;
    double x, y, z, r;
}q[M];
struct edge{               //边的两端点s,e,边权w(通道的长度);
    int s, e;
    double w;
}E[M*M];                   //存边;
bool cmp(edge a, edge b){  //sort中的cmp函数,对结构体排序;
    return a.w < b.w;
}
double between(cell a, cell b){//计算两space station通道长度函数;
    double dis;
    dis=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(dis<=0) return 0;     //if 距离小于等于0,说明两space station相交或接触,通道为0;
    else return dis;         //否则通道值即为距离值;
}
int find(int x){             //并查集中find()函数的递归写法;
    return x==uset[x]? x : uset[x]=find(uset[x]);
}
bool link(int x, int y){     //连接两点;
    int fx, fy;
    fx=find(x);
    fy=find(y);
    if(fx==fy) return false;
    else{
        uset[fy]=find(fx);
        return true;
    }
}
void Kruskal(){
    int i, j, k;
    sort(E+1, E+1+cnt, cmp);//对边排序;
    for(i=1; i<=n; i++)
        uset[i]=i;
    double sum=0.0;
    int ct=0;
    for(i=1; i<=cnt; i++){         //遍历边;
        if(link(E[i].s, E[i].e)){  //判断该边的两端点是否已经相连,没连就加上该边,已连就看下一条边;
            sum+=E[i].w;
            ct++;
            if(ct==n-1)            //直到找到n-1条边,跳出循环;
                break;
        }
    }
    printf("%.3f\n",sum);
    return;
}
int main(){
    while(scanf("%d",&n),n){
        int i, j;
        cnt=0;
        for(i=1; i<=n; i++){
            scanf("%lf%lf%lf%lf",&q[i].x,&q[i].y,&q[i].z,&q[i].r);
            for(j=1; j<i; j++){
                double dis;
                dis=between(q[j], q[i]);
                E[++cnt].s=j;
                E[cnt].e=i;
                E[cnt].w=dis;
            }
        }
        Kruskal();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值