ACM/ICPC 之 Kruskal范例(ZOJ1203-POJ1861(ZOJ1542))

  两道最小生成树范例,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 }

 

 

 

POJ1861(ZOJ1542)-Network

 

  题意:找出可连通网络中最长的网线长度在所有方案中最小的方案,依次输出使用的最长边长边数各边端点信息Special Judge

  题解:Sample貌似有可能是是在提醒Special Judge,也有可能是出错了,但是这个Sample确实有点…误导人…

     读英文需要注意理解题意   //the maximum length of a single cable is minimal. 

     其实就是在求一个最小生成树,思路参照上题,注意记录使用过的边。

 

 1 //Kruskal-除了样例和英文有点坑
 2 //Time:79Ms    Memory:348K
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<algorithm>
 7 using namespace std;
 8 
 9 #define MAXN 1005
10 #define MAXM 15005
11 
12 struct Edge {
13     int u, v;
14     int d;
15     friend bool operator < (Edge e1, Edge e2) { return e1.d < e2.d; }
16 }e[MAXM];
17 
18 int n, m;
19 int fa[MAXN];
20 int used[MAXN];        //记录使用过的边
21 
22 //路径压缩+查父
23 int Find(int x)
24 {
25     return fa[x] < 0 ? x : fa[x] = Find(fa[x]);
26 }
27 
28 //加权合并
29 void Union(int r1,int r2)
30 {
31     int num = fa[r1] + fa[r2];
32     if (fa[r1] < fa[r2])
33     {
34         fa[r2] = r1;
35         fa[r1] = num;
36     }
37     else {
38         fa[r1] = r2;
39         fa[r2] = num;
40     }
41 }
42 
43 void kruskal()
44 {
45     memset(fa, -1, sizeof(fa));
46     int sum = 0;
47     int i = 0;
48     for (; i < m; i++)
49     {
50         int r1 = Find(e[i].u);
51         int r2 = Find(e[i].v);
52         if (r1 == r2)    continue;
53         Union(r1, r2);
54         used[sum++] = i;
55         if (sum == n - 1) break;
56     }
57     printf("%d\n", e[i].d);
58     printf("%d\n", sum);
59     for (int j = 0; j < sum; j++)
60         printf("%d %d\n", e[used[j]].u, e[used[j]].v);
61 }
62 
63 int main()
64 {
65     scanf("%d%d", &n, &m);
66     for (int i = 0; i < m; i++)
67         scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].d);
68     sort(e, e + m);
69     kruskal();
70 
71     return 0;
72 }

 

    原文作者:Inkblots
    原文地址: https://www.cnblogs.com/Inkblots/p/5357106.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞