最小生成树 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 } 

 

 
posted @ 2018-08-08 10:29  liubilan  阅读(196)  评论(0编辑  收藏  举报