Building a Space Station

Building a Space Station poj-2031

    题目大意:在一个三维平面内,给出n个球,我想把两个球连起来,使得两两之间联通,连起来的代价是两个球的球心距减去半径之和。如果两球相切或相交,则代价是0。

    注释:n<=100,坐标以及半径是double。

      想法:我们首先两个球之间的距离的运算规则Dist。运算之后我们暴力枚举每两个球之间的距离,并将他们存入到单独的边得结构体里。然后,将点的编号设为1-n,即可。最后,由于两两联通,我们用kruskal算法求最小生成树即可。

    最后,附上丑陋的代码... ...

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>//C-Free时默认开全库的...蜜汁CE 
 5 #define N 110
 6 using namespace std;
 7 double x[N],y[N],z[N],r[N];
 8 int fa[N];
 9 struct Node
10 {
11     int a;
12     int b;
13     double val;
14 }f[N*N];//由于我们f数组记录的是边的数量,所以要开到n*n。 
15 bool cmp(Node a,Node b)
16 {
17     return a.val<b.val;
18 }
19 int find(int x)
20 {
21     return fa[x]==x?x:(fa[x]=find(fa[x]));
22 }
23 inline bool merge(int x,int y)
24 {
25     x=find(x),y=find(y);
26     if(x==y)return 0;
27     fa[x]=y;return 1;
28 }
29 inline double Dist(int a,int b)//运算Dist 
30 {
31     double ans;
32     ans=sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b])+(z[a]-z[b])*(z[a]-z[b]));
33     if(ans<=r[a]+r[b]) return 0;
34     else return ans-r[a]-r[b];
35 }
36 int main()
37 {
38     int n;
39     int cnt=0;
40     while(1)
41     {
42         scanf("%d",&n);
43         if(n==0) return 0;
44         cnt=0;
45         for(int i=1;i<=n;i++)
46         {
47             scanf("%lf%lf%lf%lf",&x[i],&y[i],&z[i],&r[i]);
48         }
49         for(int i=1;i<=n;i++) fa[i]=i;
50         for(int i=1;i<=n;i++)
51         {
52             for(int j=i+1;j<=n;j++)
53             {
54                 f[++cnt].a=i;
55                 f[cnt].b=j;
56                 f[cnt].val=Dist(i,j);
57             }
58         }
59         sort(f+1,f+cnt+1,cmp);//这步很重要,别问我是怎么知道的... 
60         int count=0;
61         double ans=0;
62         for(int i=1;i<=cnt;i++)//kruskal
63         {
64             if(merge(f[i].a,f[i].b))
65             {
66                 ans+=f[i].val;
67                 count++;
68             }
69             if(count==n-1) break;
70         }
71         printf("%.3lf\n",ans);
72     }
73 }

    小结:kruskal算法比较的方便,虽然这是prim算法的课后练习题。

      错误:1.C-Free是默认开全库的,我排序的时候忘记开algorithm库了...

         2.由于这是一个选择的代价最小问题,我们可以清楚地发现这是没有误解情况的。

         3.kruskal必须保证每条边被存了且只被存了一次。

posted @ 2018-01-15 20:12  JZYshuraK_彧  阅读(204)  评论(0编辑  收藏  举报