一道最小生成树题目。题意为中文描述不多说。比起一般的最小生成树题目来说,本题需要考虑浮点数的比较,另外对边长也有限制(如题目所说:两岛之间的距离不能小于10米也不能大于1000米),也就是说在此情况下不能直接将两小岛连通。


       我的解题思路:首先计算和比较浮点数的大小要尤其注意,其次根据题意,两岛之间的距离不满足题目要求的视做无法直接连通。注意这两点之后用kruskal算法或者prim算法解决就可以了。


       下面是解题代码:kruskal解法

 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <math.h>
  4 #define N 105
  5 
  6 typedef struct side     //定义边结构体
  7 {
  8     int a, b;       //两点(岛)的下标
  9     double len;     //边长(距离)
 10 }side;
 11 
 12 typedef struct point    //定义点结构体
 13 {
 14     int x, y;   //坐标
 15 }point;
 16 
 17 point p[N];
 18 side s[N*N];
 19 int bleg[N];    //并查集使用,存储父节点
 20 int pn;     //点的数量
 21 int sn;     //边的数量
 22 int t;      //测试样例数
 23 
 24 void Init();        //初始化
 25 
 26 void Read();        //输入
 27 
 28 double Count(int i, int j);     //计算边长
 29 
 30 void Kruskal();
 31 
 32 int Mycmp(const void *a, const void *b);    //qsort比较函数
 33 
 34 int Find(int x);    //并查集查找
 35 
 36 void Union(int x, int y);   //并查集合并
 37 
 38 int Test();     //检测工程是否畅通
 39 
 40 int main()
 41 {
 42     scanf("%d", &t);
 43     while (t--)
 44     {
 45         Init();
 46         Read();
 47         Kruskal();
 48     }
 49     return 0;
 50 }
 51 
 52 void Init()         //初始化
 53 {
 54     int i;
 55     for (i=0; i<N; ++i)
 56     {
 57         bleg[i] = i;
 58     }
 59     sn = pn = 0;
 60     return;
 61 }
 62 
 63 void Read()         //输入
 64 {
 65     int i, j;
 66     scanf("%d", &pn);
 67     for (i=0; i<pn; ++i)
 68     {
 69         scanf("%d %d", &p[i].x, &p[i].y);
 70         for (j=0; j<i; ++j)     //开始计算新增的边
 71         {
 72             s[sn].a = i;
 73             s[sn].b = j;
 74             s[sn++].len = Count(i, j);
 75         }
 76     }
 77     return;
 78 }
 79 
 80 double Count(int i, int j)      //计算边长
 81 {
 82     double dx = ((double)p[i].x - p[j].x) * (p[i].x - p[j].x);
 83     double dy = ((double)p[i].y - p[j].y) * (p[i].y - p[j].y);
 84     return sqrt(dx + dy);
 85 }
 86 
 87 void Kruskal()
 88 {
 89     int i;
 90     double ans = 0;
 91     qsort(s, sn, sizeof(side), Mycmp);
 92     for (i=0; i<sn; ++i)    //忽略边长小于10的边
 93     {
 94         if (s[i].len >= 10) break;
 95     }
 96     for (; i<sn; ++i)
 97     {
 98         if (s[i].len <= 1000 && Find(s[i].a) != Find(s[i].b))       //要求边长小于等于1000
 99         {
100             ans += s[i].len;
101             Union(s[i].a, s[i].b);
102         }
103     }
104     if (Test() == 1)
105     {
106         printf("%.1f\n", 100 * ans);
107     }
108     else
109     {
110         printf("oh!\n");
111     }
112     return;
113 }
114 
115 int Mycmp(const void *a, const void *b)     //qsort比较函数
116 {
117     if ((*(side *)a).len > (*(side *)b).len)
118     {
119         return 1;
120     }
121     return -1;
122 }
123 
124 int Find(int x)     //并查集查找
125 {
126     int y = bleg[x];
127     int z;
128     while (y != bleg[y])
129     {
130         y = bleg[y];
131     }
132     while (x != bleg[x])
133     {
134         z = bleg[x];
135         bleg[x] = y;
136         x = z;
137     }
138     return y;
139 }
140 
141 void Union(int x, int y)        //并查集合并
142 {
143     int fx = Find(x);
144     int fy = Find(y);
145     bleg[fx] = fy;
146     return;
147 }
148 
149 int Test()      //检测工程是否畅通
150 {
151     int i;
152     int x = bleg[0];
153     for (i=1; i<pn; ++i)
154     {
155         if (bleg[i] != x)   //出现有两小岛不属于同一个集合时说明工程未畅通
156         {
157             return 0;
158         }
159     }
160     return 1;
161 }