[kuangbin带你飞]专题六 最小生成树 C

http://poj.org/problem?id=2031

题意:

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

tip:

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

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef pair<double,int> pii;
const int maxn = 110;
const int maxm = 10010;
const double INF = 1e8+10;
int n,tot,head[maxn];
double dist[maxn],x[maxn],y[maxn],z[maxn],r[maxn];
bool vis[maxn];
priority_queuevector,greater >q;

struct node{
    int v,next;
    double w;
}edges[maxm];

void add(int u,int v,double w){
    edges[tot].v=v;edges[tot].w=w;edges[tot].next=head[u];head[u]=tot++;
    edges[tot].v=u;edges[tot].w=w;edges[tot].next=head[v];head[v]=tot++;
}
double cal(int i,int j){
    double dis = (x[j]-x[i])*(x[j]-x[i])+(y[j]-y[i])*(y[j]-y[i])+(z[j]-z[i])*(z[j]-z[i]);
    dis = sqrt(dis);
    if(dis <= r[j]+r[i])    return 0;
    return dis-r[j]-r[i];
}

void init(){
    tot = 0 ;
    memset(head,-1,sizeof(head));
    memset(vis,false,sizeof(vis));
    for(int i = 0 ; i <= n ; i++)   dist[i] = INF;
    for(int i = 1 ; i <= n ; i++) scanf("%lf%lf%lf%lf",&x[i],&y[i],&z[i],&r[i]);
    for(int i = 1; i <= n ; i++)
        for(int j = i+1; j <= n ; j++){
            add(i,j,cal(i,j));
        }
}

void prim(){
    q.push(make_pair(0,1));
    dist[1] = 0.0;
    while(!q.empty()){
        pii tmp = q.top();q.pop();
        if(vis[tmp.second])  continue;
        vis[tmp.second] = true;
        for(int k = head[tmp.second];k !=-1 ; k = edges[k].next){
            if(dist[edges[k].v]>edges[k].w&&!vis[edges[k].v]){
                dist[edges[k].v]=edges[k].w;
                q.push(make_pair(dist[edges[k].v],edges[k].v));
            }
        }
    }
    double ans = 0;
    for(int i = 1 ; i <= n ; i++)
        ans += dist[i];
    printf("%.3lf\n",ans);
}

int main(){
    while(~scanf("%d",&n)&&n){
        init();
        prim();
    }

}

你可能感兴趣的:(acm,带你飞系列,基本算法)