模板题,学习一下最小生成树的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 }
代码君一

相关文章: