zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    72     }
    73 }

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

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

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

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

  • 相关阅读:
    PAT Basic Level 1013
    PAT Basic Level 1012
    PAT Basic Level 1011
    PAT Basic Level 1009
    PAT Basic Level 1010
    PAT Basic Level 1008 *
    PAT Basic Level 1007 *
    .NET Entity Framework入门简介及简单操作
    SQL Server 查询处理中的各个阶段(SQL执行顺序)
    泛型优点和特性
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8289724.html
Copyright © 2011-2022 走看看