最小生成树算法
Posted dynastysun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树算法相关的知识,希望对你有一定的参考价值。
最小生成树有两种算法:Kruskal算法 和 Prim算法
算法一:Kruskal算法
基本思想就是:每次选择目前剩余的边中的权值最小的边,若将此边加入图中,不会形成环,则可以加入图中,否则舍弃。判断是否会形成环可以使用并查集算法。
以 HDU - 1879 题为例(题目链接:https://vjudge.net/problem/HDU-1879 ),代码如下:
1 #include <algorithm> 2 #include <queue> 3 #include <cstdio> 4 #include <iostream> 5 #include <cstring> 6 #include <map> 7 #include <cmath> 8 using namespace std; 9 10 const int maxn = 100 + 10; 11 int N, M; 12 13 int ans, f[maxn]; 14 15 struct Node{ 16 int x, y, d; 17 Node(int x=0,int y=0,int d=0):x(x),y(y),d(d){} 18 bool operator < (const Node& t) const { 19 return d < t.d; 20 } 21 }; 22 Node edge[maxn*maxn]; 23 24 // 并查集 25 int find(int a) { 26 return f[a] == a ? a : f[a]=find(f[a]); 27 } 28 29 void Kruskal(){ 30 for(int i = 1; i <= N; ++i) f[i] = i; 31 32 //按照边的权值从小到大进行选取 33 for(int i = 0; i < M; ++i){ 34 int u = find(edge[i].x); 35 int v = find(edge[i].y); 36 if(u != v){ 37 f[u] = v; 38 ans += edge[i].d; 39 } 40 } 41 } 42 43 int main(){ 44 while(scanf("%d", &N) == 1 && N){ 45 M = N*(N-1)/2; 46 for(int i = 0; i < M; ++i){ 47 int u, v; 48 scanf("%d%d%d%d", &edge[i].x, &edge[i].y, &u, &v); 49 if(v == 1) edge[i].d = 0; 50 else edge[i].d = u; 51 } 52 sort(edge, edge+M); 53 ans = 0; 54 Kruskal(); 55 cout << ans << endl; 56 } 57 return 0; 58 }
这个算法是按照边来计算的,所以算法复杂度为O(eloge),下面的Prim算法是依据结点来计算的,复杂度是O(n^2)
算法二:Prim算法
基本思想和Dijkstra算法思想有点类似,可以参考Dijkstra算法的思想,链接:https://www.cnblogs.com/DynastySun/p/9351584.html,代码如下:
1 #include <algorithm> 2 #include <queue> 3 #include <cstdio> 4 #include <iostream> 5 #include <cstring> 6 #include <map> 7 #include <cmath> 8 using namespace std; 9 10 const int INF = 0x3f3f3f3f; 11 const int maxn = 100 + 10; 12 13 int ans, N, M, G[maxn][maxn]; 14 15 void Prim(){ 16 int start = 1; 17 int flag[maxn], dis[maxn]; 18 memset(flag, 0, sizeof(flag)); 19 for(int i = 1; i <= N; ++i) { 20 dis[i] = G[i][1]; 21 last[i] = start; 22 } 23 dis[start] = 0; 24 flag[start] = 1; 25 for(int i = 1; i < N; ++i){ 26 int MIN = INF; 27 int k; 28 for(int j = 1; j <= N; ++j) 29 if(!flag[j] && MIN > dis[j]){ 30 MIN = dis[j]; 31 k = j; 32 } 33 34 flag[k] = 1; 35 ans += MIN; 36 37 for(int j = 1; j <= N; ++j) 38 if(!flag[j] && dis[j] > G[j][k]) { 39 dis[j] = G[k][j]; 40 } 41 } 42 } 43 44 int main(){ 45 while(scanf("%d", &N) == 1 && N){ 46 memset(G, INF, sizeof(G)); 47 M = N*(N-1)/2; 48 for(int i = 0; i < M; ++i){ 49 int a, b, c, d; 50 scanf("%d%d%d%d", &a, &b, &c, &d); 51 if(d == 1) G[a][b] = G[b][a] = 0; 52 else G[a][b] = G[b][a] = c; 53 } 54 ans = 0; 55 Prim(); 56 printf("%d ", ans); 57 } 58 return 0; 59 }
以上是关于最小生成树算法的主要内容,如果未能解决你的问题,请参考以下文章