求最小生成树的两种方法(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 }
永远热爱,永远向着光。