算法(Prim算法)
时间复杂度:\(O(n^2)\)
Prim算法伪代码:
dist[i] = 正无穷
for (i = 0; i < n; i ++ )
t 找到集合外部距离最近的点
用 t 更新其他点到集合的距离
st[t] = true
时间复杂度为\(O(V^2)\),V为顶点个数,与边数E无关,所以适合边稠密的图。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1010, INF = 0x3f3f3f3f;
int n, m; //n个点 m条边
int g[N][N]; //记录图中点到点之间的距离
int dist[N]; //记录每个点到最小生成树集合的距离
bool st[N]; //记录每个点是否在最小生成树集合中
int prim() {
LL res = 0; //记录最小生成树边权之和
//第一步:将所有点到集合的距离初始化为正无穷
memset(dist, INF, sizeof dist);
//第二步:任取一个点加入集合,初始化距离为0,利用当前点更新其他点到集合的距离
for (int i = 0; i < n; i ++ ) {
int t = -1;
for (int j = 1; j <= n; j ++ )
//若当前点不在集合 且 还没有加入点或者当前点到集合的距离更小
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
//如果不是第一个点并且到集合距离为无穷 则该点不存在
if (i && dist[t] == INF) return INF;
//将该点加入集合
if (i) res += dist[t];
st[t] = true;
//利用当前点更新其他点到集合的距离
for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
}
return res;
}
int main() {
cin >> n >> m;
//初始化图
memset(g, INF, sizeof g);
while (m -- ) {
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = min(g[a][b], c);
}
LL res = prim();
cout << res << endl;
return 0;
}
算法2(Kruskal算法)
时间复杂度:\(O(m\log m)\)
Kruskal算法伪代码:
将所有边按权重从小到大排序 //O(mlogm)
枚举每条边a,b 权重是c //O(m)
if a b 不连通
把这条边加入集合 //并查集时间复杂度O(1)
适用于边稀疏而顶点较多的图。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010, M = 100010;
int n, m;
struct Edge{
int a, b, c;
bool operator< (const Edge& E)const {
return c < E.c;
}
}edge[M];
//并查集
int p[N];
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int kruskal() {
//第一步:将所有边按权重大小排序
sort(edge, edge + m);
//并查集初始化
for (int i = 1; i <= n; i ++ ) p[i] = i;
//第二步:枚举每条边,若不连通,则把这条边加入最小生成树
int res = 0, cnt = 0; //res为最小生成树边权之和 cnt为最小生成树边的数量
for (int i = 0; i < m; i ++ ) {
int a = edge[i].a, b = edge[i].b, c = edge[i].c;
a = find(a), b = find(b);
//如果不连通,则加入这条边
if (a != b) {
p[a] = b;
cnt ++;
res += c;
}
}
if (cnt < n - 1) return -1; //没有最小生成树
else return res;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i ++ ) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
edge[i] = {a, b, c};
}
int res = kruskal();
printf("%d\n", res);
return 0;
}