ACM/ICPC 之 Kruskal范例(POJ1128(ZOJ1083))

Posted GUARDIAN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM/ICPC 之 Kruskal范例(POJ1128(ZOJ1083))相关的知识,希望对你有一定的参考价值。

  最小生成树范例,Kruskal解法-以边为主体扩展最小生成树,需要利用并查集

 


 

 

ZOJ1203-Swordfish

  

  题意:求n个给定平面坐标的城市中的一条平面距离上的最短路长(保留两位小数)

  题解:这道题数据不是很大,用Kruskal和Prim等算法都能够做。

     Kruskal的算法思路是以边为主体扩展结点,即先选取权值最少的边,将两个不连通的端点加入到同一集合中(使其连通),舍去该边,接着找权值次小的,以此类推...

     如果两个端点连通,则直接舍去该边。

     因此可以先将所有边依据权值大小排序后,然后依次查找即可,为了较快地表示两个端点连通(属于同一集合),需要用到并查集的路径压缩。

 

 1 //剑鱼行动-Kruskal
 2 //找出n个给定平面坐标的城市中的一条最短路长(保留两位小数)
 3 //Time:0Ms    Memory:432K
 4 #include<iostream>
 5 #include<cstring>
 6 #include<cstdio>
 7 #include<cmath>
 8 #include<algorithm>
 9 using namespace std;
10 
11 #define MAX    101
12 #define POW2(x) ((x)*(x))
13 
14 struct City {
15     double x, y;
16 }c[MAX];
17 
18 struct Edge {
19     int u, v;    //端点
20     double road;
21     friend bool operator < (Edge e1, Edge e2) { return e1.road < e2.road; }
22 }e[MAX*MAX];
23 
24 int n, m;
25 int fa[MAX];
26 double minroad;
27 
28 int Find(int x)
29 {
30     return fa[x] < 0? x : fa[x] = Find(fa[x]);    //查根+路径压缩
31 }
32 
33 //加权法则合并
34 void Union(int r1,int r2)
35 {
36     int num = fa[r1] + fa[r2];    //集合元素总数-以负数计数
37     if (fa[r1] > fa[r2])    //r2集合元素多
38     {
39         fa[r1] = r2;
40         fa[r2] = num;
41     }
42     else {    //r1集合元素多
43         fa[r2] = r1;
44         fa[r1] = num;
45     }
46 }
47 
48 void kruskal()
49 {
50     minroad = 0;
51     memset(fa, -1, sizeof(fa));
52     int num = 0;    //已用结点数
53     for (int i = 0; i < m; i++)
54     {
55         int r1 = Find(e[i].u);
56         int r2 = Find(e[i].v);
57         if (r1 == r2)    continue;
58         minroad += e[i].road;
59         Union(r1, r2);
60         num++;
61         if (num == n - 1) break;
62     }
63 }
64 
65 int main()
66 {
67     int cas = 0;
68     while (scanf("%d", &n), n)
69     {
70         for (int i = 0; i < n; i++)
71             scanf("%lf%lf", &c[i].x, &c[i].y);
72 
73         m = 0;
74         for (int i = 0; i < n; i++)
75             for (int j = i + 1; j < n; j++)
76             {
77                 double d = sqrt(POW2(c[i].x - c[j].x) + POW2(c[i].y - c[j].y));
78                 e[m].road = d;
79                 e[m].u = i;
80                 e[m++].v = j;
81             }
82 
83         sort(e, e + m);
84 
85         kruskal();
86         if (cas)    printf("\n");    //博主在此PE过= =
87         printf("Case #%d:\n", ++cas);
88         printf("The minimal distance is: %.2lf\n", minroad);
89     }
90 
91 
92     return 0;
93 }

 

以上是关于ACM/ICPC 之 Kruskal范例(POJ1128(ZOJ1083))的主要内容,如果未能解决你的问题,请参考以下文章

ACM/ICPC 之 拓扑排序-反向(POJ3687)

ACM/ICPC 之 经典动规(POJ1088-滑雪)

ACM/ICPC 之 欧拉回路两道(POJ1300-POJ1386)

ACM/ICPC 之 DP进阶(51Nod-1371(填数字))

ACM/ICPC 之 拓扑排序+DFS(POJ1128(ZOJ1083))

ACM/ICPC 之 BFS-简单障碍迷宫问题(POJ2935)