一、Prim
Prim算法的思想是:
- 整个顶点集为\(V\),初始选一个起点\(s\),令集合\(u=\{s\}, v=\{\}\);
- 在集合\(u\)与集合\(V-u\)中的点组成的边中,选一条权值最小的边\(u_0v_0\)加入MST,并且将\(u_0\)加入\(u\);
- 重复直到MST有\(n-1\)条边或\(n\)个顶点为止。
int adjMax[MAXN][MAXN]; //邻接矩阵 int n; //顶点数目 int pos = 0, ans = 0; bool visited[MAXN] = {0}, cost[MAXN]; void Prim() { for (int i = 0; i < n; i++) { cost[i] = adjMax[0][i]; //集合u与集合V-u中的i点间距离最小值 visited[i] = false; } visited[0] = true; //已经在MST中 for (int i = 1; i < n; i++) //再找n-1个点 { //找到连接u和V-u的最小边并记录位置 int tmp = INT_MAX; for (int j = 0; j < n; j++) { if (visited[j] == false && cost[j] < tmp) { tmp = cost[j]; pos = j; } } ans += tmp; visited[pos] = true; //加入某点后,V-u中的点j到u的距离可能变短,故更新cost[j] for (int j = 0; j < n; j++) { if (visited[j] == false && cost[j] > adjMax[pos][j]) { cost[j] = adjMax[pos][j]; } } } }
性能:邻接矩阵表示不依赖于边数,复杂度\(O(|V|^2)\),适合边稠密的图。
二、Kruskal
该算法思想:将所有边的权值递增排序,如果加入某边后不构成回路,则将该边加入MST,直到MST中有\(n-1\)条边或\(n\)个顶点:
//用结构体存储边的信息 struct edge { int start, des; int val; }edge[MAXN]; //用并查集判断有没有环 int UFSets[MAXN]; for (int i = 0; i < n; i++) { UFSets[i] = -1; } //在S中查找并返回包含x的树的根 int find(int S[],int x) { while (S[x] >= 0) x = S[x]; return x; } void kruskal() { for (int i = 0; i < m; i++) { int u = find(UFSets, edge[i].start); int v = find(UFSets, edge[i].des); if (u == v) //edge[i]的两端点有相同的祖先,成环 continue; ans += edge[i].val; UFSets[u] = v; //合并两个并查集 cnt++; if (cnt == n - 1) break; } }
性能:复杂度\(O(ElogE)\),适合边稀疏、顶点多的图。
来源:https://www.cnblogs.com/EIMadrigal/p/12234280.html