C - Building a Space Station POJ2031 最小生成树

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAXN = 1e4 + 10;//拿来开存边的数量的结构体 题目N<100 所以最多开到N*N也就是1e4就够了 
const int maxn = 110;//用于开存点的数量结构体 
struct node {//用于储存输入的点 
    double x, y, z, r;
}ball[maxn];
struct P {//用于储存转换后的边 代表点 x 到 y 的距离 
    int x, y;
    double dis;
    bool friend operator<(const P& a, const P& b) {
        return a.dis < b.dis;
    }
}p[MAXN];
int parent[MAXN];
int get(int x) {
    return parent[x] == x ? x : parent[x] = get(parent[x]);
}
void merge(int x, int y) {
    parent[get(x)] = get(y);
}
double distan(node a, node b) {//用于求两个点的距离 
    double 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));
    if (dis <= a.r + b.r) return 0;//如果两个球相交或者相切 那么他们的距离就是0 
    else return (dis - a.r - b.r);
}
int all = 1;//用于表示转换之后边的数量 
void change(int x, int y, double dis) {//把两个点转换为边的表现形式的函数 
    p[all].x = x;
    p[all].y = y;
    p[all++].dis = dis;
}
int main(void) {
    int N;
    while (scanf("%d", &N), N) {
        all = 1;
        for (int i = 1; i <= N; i++) parent[i] = i;
        for (int i = 1; i <= N; i++) {
            scanf("%lf%lf%lf%lf", &ball[i].x, &ball[i].y, &ball[i].z, &ball[i].r);
        }
        for (int i = 1; i <= N; i++) {
            for (int j = i + 1; j <= N; j++) {
                double dis = distan(ball[i], ball[j]);//遍历第一个点到第二、三……N个点 然后第二个点到第三、四……N个点…… 第N-1到第N个点的边 
                change(i, j, dis);//把第i个点到第j个点距离为dis的数据存到p结构体中 
            }
        }
        all--;
        sort(p + 1, p + all+1);//按照距离从小到大排序 
        int cnt = 0;
        double ans = 0;
        for (int i = 1; i <= all; i++) {
            int fx = get(p[i].x), fy = get(p[i].y);
            if (fx == fy) continue;
            merge(fx, fy);
            cnt++;
            ans += p[i].dis;
            if (cnt == N - 1) break;
        }
        printf("%.3lf\n", ans);
    }
    return 0;
}

 

posted @ 2020-02-05 13:52  programmer_w  阅读(7)  评论(0)    收藏  举报