图的一些概念
具体看先前的一篇文章https://www.wztlink1013.com/blog/gqpli5/
连通图
在图论中,连通图基于连通的概念。在一个无向图 G 中,若从顶点i到顶点j有路径相连(当然从j到i也一定有路径),则称i和j是连通的。如果 G 是有向图,那么连接i和j的路径中所有的边都必须同向。如果图中任意两点都是连通的,那么图被称作连通图。如果此图是有向图,则称为强连通图(注意:需要双向都有路径)。图的连通性是图的基本性质。
生成树
包含图的全部顶点,边数最少的连通子图
最小生成树
总权值最小的生成树
常见问题(该算法)就是求最小生成树。
并查集
是一个数据结构,功能有查找a和b是否为同一组;将a和b合并为同一组。
Prim算法思路
Prim——普里姆算法
类似于图的深度优先遍历一样,在遍历到一个结点的时候,在此根据该节点所连通的各边权值,取最小的,以此往复
Kruskal算法思路
Kruskal——克鲁斯卡尔算法
把所有边按照权值全部按数值大小拿出来,然后按顺序选取每条边,利用并查集的思想,如果这条边的两个端点不属于同一集合,那么就将它们合并,直到所有的点都属于同一个集合为止。
比如有如下这么一个图:
单独分析①②边和③④边情况下,两个不在一个集合里面,
不断重复,不断判断是否为同一个集合,不在同一个集合的话,就合并,持续如此。比方说当一直操作到权值为3的时候,此时就需要将左右两个集合合并了
最后的结果样式就为如下
代码实现
Kruskal算法代码
#include <stdio.h>#include <vector>#include <algorithm>namespace NS_KruskalMST {using namespace std;void KruskalMST();int FindSet(int u);void UnionSets(int u, int v);void Initialization();void GenEdges();void MakeSets();void Output(int v0);#define INF INT_MAXstatic int n;static vector<vector<int>> WMatrix;static vector<pair<pair<int, int>, int>> Edges;//Node struct for the disjoint setstruct DJSNode {int Parent; int Rank;DJSNode(int p) : Parent(p), Rank(0) {}};static vector<DJSNode> DisjointSet;static vector<pair<int, int>> MST;//The adjacency list for MSTstatic vector<vector<int>> MSTList;static vector<int> Prev;void KruskalMSTCaller(int an,vector<vector<int>> &wMatrix, int v0){n = an;WMatrix = wMatrix;Initialization();KruskalMST();Output(v0);}void KruskalMST(){for (auto &e: Edges){int u = e.first.first;int v = e.first.second;int setU = FindSet(u);int setV = FindSet(v);if (setU != setV){MST.push_back(e.first);if (MST.size() == n - 1)break;UnionSets(setU, setV);}}}int FindSet(int u){while (u != DisjointSet[u].Parent)u = DisjointSet[u].Parent;//For path compression://DisjointSet[u].Parent =// FindSet(DisjointSet[u].Parent);return u;}void UnionSets(int u, int v){if (DisjointSet[u].Rank >= DisjointSet[v].Rank)DisjointSet[v].Parent = u;elseDisjointSet[u].Parent = v;if (DisjointSet[u].Rank == DisjointSet[v].Rank)DisjointSet[u].Rank++;}void Initialization(){GenEdges();sort(Edges.begin(), Edges.end(),[](pair<pair<int, int>, int>a,pair<pair<int, int>, int>b){return a.second < b.second; });MakeSets();MST.clear();}void GenEdges(){Edges.clear();//Traverse the upper triangle of WMatrixfor (int i = 0; i < n - 1; i++){for (int j = i + 1; j < n; j++)if (WMatrix[i][j] != INF)Edges.push_back({ {i, j},WMatrix[i][j] });}}void MakeSets(){DisjointSet.clear();for (int i = 0; i < n; i++)DisjointSet.push_back(DJSNode(i));}void OutputWMatrix(){printf("n = %d\n", n);printf("The weight matrix:\n");printf("%3c", ' ');for (int j = 0; j < n; j++)printf("%3d", j + 1);printf("\n");for (int i = 0; i < n; i++){printf("%3d", i + 1);for (auto j : WMatrix[i])if (j < INF)printf("%3d", j);elseprintf("%3c", '*');printf("\n");}}void OutputPath(int u){if (Prev[u] == -1)printf("%d", u + 1);else{OutputPath(Prev[u]);printf("-%d", u + 1);}}void GenMSTList(){MSTList.clear();MSTList.resize(n);for (auto &e: MST){MSTList[e.first].push_back(e.second);MSTList[e.second].push_back(e.first);}}void GenPrev(int v){for (auto &u : MSTList[v])if (u != -1){Prev[u] = v;auto w = find(MSTList[u].begin(),MSTList[u].end(), v);MSTList[u][w - MSTList[u].begin()] = -1;GenPrev(u);}}void Output(int v0){printf("Kruskal's MST algorithm\n");OutputWMatrix();int wSum = 0;for (int i = 0; i < n - 1; i++)wSum += WMatrix[MST[i].first][MST[i].second];GenMSTList();Prev.clear();Prev.resize(n);Prev[v0] = -1;GenPrev(v0);printf("The MST edges:\n");printf("Edge Weight\n");for (auto &e : MST)printf(" %d-%d %d\n", e.first + 1, e.second + 1,WMatrix[e.first][e.second]);printf("Total MST weight: %d\n", wSum);printf("The MST paths from vertex %d:\n", v0 + 1);for (int u = 0; u < n; u++)if (u != v0){printf("%3d: ", u + 1);OutputPath(u);printf("\n");}printf("\n");}} //namespace NS_KruskalMSTusing namespace NS_KruskalMST;void TestKruskalMST(int v0 = 0){vector<vector<vector<int>>> w = {//https://www.geeksforgeeks.org///prims-minimum-spanning-tree-mst-greedy-algo-5/{{ 0, 2,INF, 6,INF },{ 2, 0, 3, 8, 5 },{ INF, 3, 0,INF, 7 },{ 6, 8,INF, 0, 9 },{ INF, 5, 7, 9, 0 }},// Dijkstra's algorithm on Wikipedia{{ 0, 7, 9,INF,INF, 14 },{ 7, 0, 10, 15,INF,INF },{ 9, 10, 0, 11,INF, 2 },{ INF, 15, 11, 0, 6,INF },{ INF,INF,INF, 6, 0, 9 },{ 14,INF, 2,INF, 9, 0 },},//https://www.geeksforgeeks.org///kruskals-minimum-spanning-tree-using-stl-in-c/{{ 0, 4,INF,INF,INF,INF,INF, 8,INF },{ 4, 0, 8,INF,INF,INF,INF, 11,INF },{ INF, 8, 0, 7,INF, 4,INF,INF, 2 },{ INF,INF, 7, 0, 9, 14,INF,INF,INF },{ INF,INF,INF, 9, 0, 10,INF,INF,INF },{ INF,INF, 4, 14, 10, 0, 2,INF,INF },{ INF,INF,INF,INF,INF, 2, 0, 1, 6 },{ 8, 11,INF,INF,INF,INF, 1, 0, 7 },{ INF,INF, 2,INF,INF,INF, 6, 7, 0 },},};int k = w.size();for (int i = 0; i < k; i++){if (v0 > w[i].size() - 1)v0 = w[i].size() - 1;KruskalMSTCaller(w[i].size(), w[i], v0);}}
