最小生成树 prim & kruskal
给定一个无向图,如果他的某个子图中,任意两个顶点都能互相连通并且是一棵树,那么这棵树就叫做生成树(spanning tree).
如果边上有权值,那么使得边权和最小的生成树叫做最小生成树(MST,Minimum Spanning Tree)
1. prim算法:
使用临界矩阵存储边,适用于两点之间只有一条边,或只需要保存最短或最长的一条边的情况。
通过“加点”搜索最短路径;
附代码,这里假设为无向图:
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 #define INF 1e9 6 const int N = 100+5; //number of dots 7 int n,m; 8 int dis[N], vis[N], edge[N][N]; 9 10 void init() 11 { 12 memset(vis, 0, sizeof(0)); 13 vis[0]=1, dis[0]=0; //start from 0 14 15 for(int i=0; i<n; i++) 16 for(int j=0; j<N; j++) 17 edge[i][j]=INF; 18 } 19 20 int prim() 21 { 22 int mini, minx, count=0, cost=0; 23 while(count<n) { 24 mini = -1; 25 minx = INF; 26 for(int i=1; i<n; i++) { 27 if(!vis[i] && dis[i]<minx) { 28 mini = i; 29 minx = dis[i]; 30 } 31 } 32 if(mini == -1) return -1; 33 34 vis[mini] = 1; 35 cost += minx; 36 count++; 37 38 for(int i=1; i<n; i++) { 39 if(!vis[i] && edge[mini][i]<dis[i]) 40 dis[i] = edge[mini][i]; 41 } 42 } 43 return cost; 44 } 45 46 int main() 47 { 48 cin>>n>>m; 49 init(); 50 for(int a,b,v,i=0; i<m; i++) { 51 cin>>a>>b>>v; 52 edge[a][b] = edge[b][a] = v; //undirected graph 53 } 54 55 prim(); 56 57 return 0; 58 }
2. kruskal算法
通过“加边”搜索最短路径;
按照边的权值从小到大排序,再全部访问一遍,如果将该边加入当前生成树内不会产生环,那么就把这条边加入到生成树中,逐步扩大生成树的大小。
接下来我们介绍如何判断是否产生重边。假设现在要把连接顶点u和顶点v的边e(u—>v,v—>u)加入到生成树中去,如果加入操作之前,u和v不在同一个连通分量内(两块不连接的图),那么加入e也不会产生圈。反之,如果u和v在同一个连通分量里,那么一定会产生圈。可以使用并查集判断是否属于同一个连通分量。
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 #define INF 1e9 7 const int N = 100+5; //number of dots 8 const int M = 1000+5; 9 int n,m; 10 struct Edge { 11 int from, to, value; 12 bool operator<(const Edge &a) { 13 return value<a.value; 14 } 15 }edge[M]; 16 int vis[N], f[N]; 17 18 int find(int x) 19 { 20 if(x != f[x]) 21 f[x] = find(f[x]); 22 return f[x]; 23 } 24 25 void init() 26 { 27 for(int i=0; i<n; i++) 28 vis[i]=0, f[i] = i; 29 sort(edge, edge+m); 30 } 31 32 int kruskal() 33 { 34 int cost=0; 35 for(int i=0; i<m; i++) { 36 int x = find(edge[i].from); 37 int y = find(edge[i].to); 38 if(x != y) { 39 f[x] = y; 40 cost += edge[i].value; 41 vis[edge[i].from] = vis[edge[i].to] = 1; 42 } 43 } 44 } 45 46 int main() 47 { 48 cin>>n>>m; 49 for(int i=0; i<m; i++) 50 cin>>edge[i].from>>edge[i].to>>edge[i].value; 51 52 init(); 53 kruskal(); 54 55 return 0; 56 }