[Kruskal] POJ 2031

题意:

给定一些球的圆心与半径,如果两个球之间相交,则他们之间连通,
否则不连通,问还需要连多长的边使所有球都连通

思路:

任意两个球,如果连通则边权为0,
否则边权为d-r1-r2,d是两球圆心坐标之间的距离,r1与r2分别为两个球的半径,
这样求一个最小生成树,将所有球连接起来

数据double类型的时候,用G++的时候scanf要用%lf,而printf的时候要用%f,否则会WA

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>

#define maxn 110
#define maxm 100110
#define INF 0x7f7f7f7f

using namespace std;

struct Edge {
    int u, v;
    double dis;
    Edge () {}
    Edge ( int u, int v, double d )
        : u ( u )
        , v ( v )
        , dis ( d ) {}
    bool operator< ( const Edge &rhs ) const { return dis < rhs.dis; }
};

struct Kruskal {
    int n, m;
    int fa[ maxn ];
    Edge edg[ maxm ];

    void init ( int n ) {
        this->n = n;
        m = 0;
        memset ( fa, -1, sizeof ( fa ) );
    }

    int findset ( int x ) { return fa[ x ] == -1 ? x : fa[ x ] = findset ( fa[ x ] ); }

    void AddEdge ( int u, int v, double dis ) { edg[ m++ ] = Edge ( u, v, dis ); }

    double kruskal () {
        double sum = 0;
        int cnt = 0;
        sort ( edg, edg + m );

        for ( int i = 0; i < m; ++i ) {
            int u = edg[ i ].u;
            int v = edg[ i ].v;
            if ( findset ( u ) != findset ( v ) ) {
                sum += edg[ i ].dis;
                // UNION
                fa[ findset ( u ) ] = findset ( v );
                if ( ++cnt >= n - 1 )
                    break;
            }
        }
        return sum;
    }
} KK;

struct Point {
    double x, y, z, r;
} p[ maxn ];

//求两个cell之间的距离是否能直接连通
double getdis ( int i, int j ) {
    double len = sqrt ( ( p[ i ].x - p[ j ].x ) * ( p[ i ].x - p[ j ].x ) +
                        ( p[ i ].y - p[ j ].y ) * ( p[ i ].y - p[ j ].y ) +
                        ( p[ i ].z - p[ j ].z ) * ( p[ i ].z - p[ j ].z ) );
    double ans = len - p[ i ].r - p[ j ].r;
    if ( ans < 0 )
        return 0;
    else
        return ans;
}

int main () {
    int n;
    while ( ~scanf ( "%d", &n ) && n ) {
        for ( int i = 0; i < n; ++i )
            scanf ( "%lf%lf%lf%lf", &p[ i ].x, &p[ i ].y, &p[ i ].z, &p[ i ].r );
        KK.init ( n );
        for ( int i = 0; i < n; ++i )
            for ( int j = i + 1; j < n; ++j )
                KK.AddEdge ( i, j, getdis ( i, j ) );
        double sol = KK.kruskal ();
        printf ( "%.3f\n", sol );
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值