求最小生成树的两种方法(prim算法和kruskal算法)

先存一下我写的prim和kruskal求最小生成树的模板,具体实现思路等我有时间的再写。。。

prim代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<map>
 6 #include<queue>
 7 #include<set>
 8 #include<cmath>
 9 #include<list>
10 #include<cstring>
11 #include<string>
12 #define ll long long
13 #define ull unsigned long long
14 #define inf 0x3f3f3f3f
15 #define inff 0x7fffffff
16 using namespace std;
17 const int N = 500 + 10;
18 const int M = 100000 + 10;
19 
20 int G[N][N], vis[N], lowc[N];            //其中lowc数组记录所有已标记点到无标记点的最短路径,vis数组标记已遍历的点
21 
22 int prim(int n) {
23     
24     int ans = 0;
25     memset(vis, 0, sizeof(vis));
26     vis[1] = 1;                    //将已遍历的点标记
27     for (int i = 1; i <= n; i++) lowc[i] = G[1][i];  //求从顶点1出发,到每个点的距离,如果为inf则无法到达
28     for (int i = 2; i <= n; i++) {   // 求n - 1条边
29         int minc = inf;
30         int p = -1;
31         for (int j = 1; j <= n; j++) {            //寻找所有已标记点到无标记点的最短路径
32             if (!vis[j] && minc > lowc[j]) {
33                 minc = lowc[j];
34                 p = j;
35             }
36         }
37         if (minc == inf) return -inf;            //如果没找到,则说明原图不连通
38         ans += minc;
39         vis[p] = 1;
40         for (int j = 1; j <= n; j++) {                    //更新lowc数组记录的值
41             if (!vis[j] && lowc[j] > G[p][j]) {            
42                 lowc[j] = G[p][j];
43             }
44         }
45     }
46 
47     return ans;
48 }
49 
50 int main() {
51     
52     int n, m;
53     cin >> n >> m;
54     memset(G, 0x3f, sizeof(G));
55     for (int i = 1; i <= m; i++) {
56         int u, v, d;
57         cin >> u >> v >> d;
58         G[u][v] = min(G[u][v], d);
59         G[v][u] = min(G[u][v], G[v][u]);
60     }
61     int ans_f = prim(n);
62     if (ans_f == -inf) cout << "impossible" << "\n";
63     else cout << ans_f << "\n";
64 
65     return 0;
66 }

 kruskal代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<map>
 6 #include<queue>
 7 #include<set>
 8 #include<cmath>
 9 #include<list>
10 #include<cstring>
11 #include<string>
12 #define ll long long
13 #define ull unsigned long long
14 #define inf 0x3f3f3f3f
15 #define inff 0x7fffffff
16 using namespace std;
17 const int N = 100000 + 10;
18 const int M = 200000 + 10;
19 
20 int fa[N];            //并查集判断是否形成闭环
21 int tol;
22 
23 struct Edge {
24     int u, v, w;
25 }edge[M];            //存边的信息
26 
27 void addedge(int u, int v, int w) {            //建边
28     edge[tol].u = u;
29     edge[tol].v = v;
30     edge[tol++].w = w;
31 }                        
32 
33 bool cmp(Edge a, Edge b) {            //按照权值将边从小到大排序
34     return a.w < b.w;
35 }
36 
37 int finds(int x) {                    //并查集求两个点是否形成闭环
38     if (fa[x] == -1) return x;
39     else return fa[x] = finds(fa[x]);
40 }
41 
42 int kruskal(int n) {                //n表示点的数目
43 
44     memset(fa, -1, sizeof(fa));
45     sort(edge, edge + tol, cmp);    //按边的权值排序,以便后续操作中总是优先选择权值最小的边
46     int cut = 0;                    //记录求得的边数
47     int ans = 0;                    
48     for (int i = 0; i < tol; i++) {
49         int u = edge[i].u;
50         int v = edge[i].v;
51         int w = edge[i].w;
52         int t1 = finds(u);
53         int t2 = finds(v);
54         if (t1 != t2) {                //如果祖先不相等说明两点不存在闭环,可以加这条边
55             fa[t1] = t2;
56             ans += w;
57             cut++;
58         }
59         if (cut == n - 1) break;
60     }
61     if (cut < n - 1) return -1;        //如果找不到n - 1条边,说明此图不连通
62     else return ans;
63 
64 }
65 
66 int main() {
67     
68     int n, m;
69     cin >> n >> m;
70     for (int i = 0; i < m; i++) {
71         int u, v, w;
72         cin >> u >> v >> w;
73         addedge(u, v, w);
74     }
75     int ans_f = kruskal(n);
76     if (ans_f == -1) cout << "impossible" << "\n";
77     else cout << ans_f << "\n";
78 
79     return 0;
80 }

 

 
 
 
posted @ 2022-04-10 16:19  Keyzee  阅读(50)  评论(0编辑  收藏  举报