poj2031 Building a Space Station

本文解决了一个计算几何问题,通过求解最小生成树来确定连接多个球形空间站所需的最短管道总长度。使用C++实现克鲁斯卡尔算法。

这题目,用G++ WA,用C++ AC。

 

题目要求,现给出n个球,然后要使每两个球直接或者间接连通,可以在任意两球之间做管道(在表面),最后的要求是,如果使得都连通的话,管道最小长度是多少。

 

思路简单,就是求出来每两个球之间的距离,球心差减去两球的半径,注意如果这里是负的则处理为0。然后就是克鲁斯卡尔求最小生成树就可以了。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <math.h>
  4 #include <string.h>
  5 #include <algorithm>
  6 #define  eps 0.00000001
  7 struct point{
  8     double x,y,z,r;
  9 }p[105];
 10 struct edge{
 11     int u,v;
 12     double w;
 13 }e[105*105];
 14 int parent[105];
 15 int n,cnt;
 16 void ufset(){
 17     int i;
 18     for(i=0;i<=n;++i)    parent[i]=-1;
 19     return;
 20 }
 21 int find(int x){
 22     int s;
 23     for(s=x;parent[s]>=0;s=parent[s]);
 24     while(s!=x){
 25         int tmp=parent[x];
 26         parent[x]=s;
 27         x=tmp;
 28     }
 29     return s;
 30 }
 31 void Union(int R1,int R2){
 32     int r1=find(R1),r2=find(R2);
 33     int tmp=parent[r1]+parent[r2];
 34     if(parent[r1]>parent[r2]){
 35         parent[r1]=r2;    parent[r2]=tmp;
 36     }else{
 37         parent[r2]=r1;    parent[r1]=tmp;
 38     }
 39     return;
 40 }
 41 int cmp(struct edge a,struct edge b){
 42     return eps<b.w-a.w;
 43 }
 44 double kruskal(){
 45     double sumweight=0;
 46     int i;
 47     int num=0;
 48     int u,v;
 49     ufset();
 50     for(i=0;i<cnt;++i){
 51         u=e[i].u;    v=e[i].v;
 52         if(find(u)!=find(v)){
 53             sumweight+=e[i].w;    num++;
 54 //            printf("sumweight=%lf,u=%d,v=%d\n",sumweight,u,v);
 55             Union(u,v);
 56         }
 57         if(num>=n-1) break;
 58     }
 59     return sumweight;
 60 }
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 double count(struct point a,struct point b){
 69     double res;
 70     res=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 ;
 71     if( 0-res > eps ) res=0;
 72     return res;
 73 }
 74 
 75 
 76 
 77 int main(){
 78     int i,j;
 79     while(~scanf("%d",&n)){
 80         if(n==0) break;
 81         for(i=0;i<n;++i){
 82             scanf("%lf%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z,&p[i].r);
 83         }
 84         cnt=0;
 85         for(i=0;i<n;++i){
 86             for(j=0;j<i;++j){
 87                 e[cnt].u=i;
 88                 e[cnt].v=j;
 89                 e[cnt].w=count(p[i],p[j]);
 90                 cnt++;
 91             }
 92         }
 93         std::sort(e,e+cnt,cmp);
 94 //        for(i=0;i<cnt;++i){
 95 //            printf("%lf\n",e[i].w);
 96 //        }
 97 //        printf("------------\n");
 98         double res=kruskal();
 99         printf("%.3lf\n",res);
100     }
101     return 0;
102 }
计算几何+克鲁斯卡尔

 

posted on 2014-01-01 20:10 symons 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/symons1992/p/3500876.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值