最小生成树之Kruskal

模板题,学习一下最小生成树的Kruskal算法

 

对于一个连通网(连通带权图,假定每条边上的权均为大于零的实数)来说,每棵树的权(即树中所有边的权值总和)也可能不同

具有权最小的生成树称为最小生成树

生成树:

  • 无向连通图的边的集合
  • 无回路
  • 连接所有的点

最小:

  • 所有边的权值之和最小

n个顶点的树有n-1条边

时间复杂度:O(ElogE)

 

对于稀疏图来说

按所给的边的权值从小到大排序,如果该边不与已经选的边形成环就选择它

这里用并查集来实现

第i条边的端点放在u、v数组中,权值保存在w中

这里用的是间接排序,也就是排的是每条边的序号,放在rank数组中

 

下面是两道模板题:

HDU 1863 畅通工程

 1 //#define LOCAL
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int maxn = 5000;
 8 int u[maxn], v[maxn], w[maxn], parent[maxn], rank[maxn];
 9 int m, n;
10 
11 bool cmp(const int i, const int j)
12 {
13     return (w[i] < w[j]);
14 }
15 
16 int GetParent(int a)
17 {
18     return parent[a] == a ? a : parent[a] = GetParent(parent[a]);
19 }
20 
21 int kruskal(void)
22 {
23     int cnt = 0, weight = 0;
24     for(int i = 0; i < m; ++i)
25     {
26         int edge = rank[i];
27         int x = GetParent(u[edge]);
28         int y = GetParent(v[edge]);
29         if(x != y)
30         {
31             weight += w[edge];
32             ++cnt;
33             parent[x] = y;
34         }
35     }
36     if(cnt < n - 1)    weight = 0;
37     return weight;
38 }
39 
40 int main(void)
41 {
42     #ifdef LOCAL
43         freopen("1863in.txt", "r", stdin);
44     #endif
45 
46 
47     while(scanf("%d%d", &m, &n) == 2 && m)
48     {
49         for(int i = 0; i < m; ++i)
50             scanf("%d%d%d", &u[i], &v[i], &w[i]);
51         for(int i = 0; i < n; ++i)    parent[i] = i;
52         for(int i = 0; i < m; ++i)    rank[i] = i;
53         sort(rank, rank + m, cmp);
54         int ans = kruskal();
55         if(ans)
56             printf("%d\n", ans);
57         else
58             printf("?\n");
59     }
60     return 0;
61 }
代码君一

 

POJ 1861 Network

感觉这道题略坑啊,它并没有说是多组输入啊,而且输出的第一个数是边里面的最大权值啊,数组开了1000多开小了啊,还有各种小错误啊。Orz

好吧,这些都是我的错误,上来就套模板,没有好好读题

 1 //#define LOCAL
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int maxn = 1000 + 10;
 9 int v[maxn], u[maxn], r[maxn], p[maxn], w[maxn], path[maxn];
10 int n, m, cnt, ans;
11 
12 int Find(int a)
13 {
14     return p[a] == a ? a : p[a] = Find(p[a]);
15 }
16 
17 bool cmp(const int i, const int j)
18 {
19     return (w[i] < w[j]);
20 }
21 
22 void Kruskal(void)
23 {
24     cnt = 0, ans = -1;
25     for(int i = 0; i < m; ++i)
26     {
27         int edge = r[i];
28         int x = Find(u[edge]);
29         int y = Find(v[edge]);
30         if(x != y)
31         {
32             ans = max(ans, w[edge]);
33             p[x] = y;
34             path[cnt++] = i;
35         }
36     }
37 }
38 
39 void OutPut(void)
40 {
41     printf("%d\n%d\n", ans, cnt);
42     for(int i = 0; i < cnt; ++i)
43         printf("%d %d\n", u[r[path[i]]], v[r[path[i]]]);
44 }
45 
46 int main(void)
47 {
48     #ifdef LOCAL
49         freopen("1861in.txt", "r", stdin);
50     #endif
51 
52     while(scanf("%d%d", &n, &m) == 2)
53     {
54         for(int i = 0; i < m; ++i)
55         scanf("%d%d%d", &u[i], &v[i], &w[i]);
56         for(int i = 0; i < n; ++i)    p[i] = i;
57         for(int i = 0; i < m; ++i)    r[i] = i;
58         sort(r, r + m, cmp);
59         Kruskal();
60         OutPut(); 
61     }
62     
63     return 0;
64 }
代码君二

 

POJ 2560 Freckles

题意:给出n个点的坐标,求最小生成树的长度。奇怪的是G++没过,C++却过了

 1 //#define LOCAL
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 #include <cmath>
 7 using namespace std;
 8 
 9 const int maxn = 5000 + 10;
10 struct Node
11 {
12     double x, y;
13 }pos[maxn];
14 
15 int u[maxn], v[maxn], r[maxn], p[maxn];
16 double w[maxn];
17 
18 bool cmp(const int i, const int j)
19 {
20     return (w[i] < w[j]);
21 }
22 
23 int Find(int a)
24 {
25     return p[a] == a ? a : p[a] = Find(p[a]);
26 }
27 
28 double Kruskal(int cnt)
29 {
30     double ans = 0.0;
31     for(int i = 0; i < cnt; ++i)
32     {
33         int edge = r[i];
34         int x = Find(u[edge]);
35         int y = Find(v[edge]);
36         if(x != y)
37         {
38             ans += w[edge];
39             p[x] = y;
40         }
41     }
42     return ans;
43 }
44 
45 int main(void)
46 {
47     #ifdef LOCAL
48         freopen("2560in.txt", "r", stdin);
49     #endif
50 
51     int n, cnt;
52     while(scanf("%d", &n) == 1)
53     {
54         for(int i = 0; i < n; ++i)    p[i] = i;
55         for(int i = 0; i < n; ++i)
56             scanf("%lf %lf", &pos[i].x, &pos[i].y);
57         cnt = 0;
58         for(int i = 1; i < n; ++i)
59             for(int j = 0; j < i; ++j)
60             {
61                 u[cnt] = i;
62                 v[cnt] = j;
63                 r[cnt] = cnt;
64                 w[cnt++] = sqrt((pos[i].x-pos[j].x)*(pos[i].x-pos[j].x) + (pos[i].y-pos[j].y)*(pos[i].y-pos[j].y));
65             }
66         sort(r, r + cnt, cmp);
67         printf("%.2lf\n", Kruskal(cnt));
68     }
69     
70     return 0;
71 }
代码君三

 

posted @ 2014-09-05 18:48  AOQNRMGYXLMV  阅读(168)  评论(0编辑  收藏  举报