Kruskal算法原理:
(1)将图结构中的边按照权值从小到大进行排序处理。
(2)每次取其中权值最小的边考虑加入到最小生成树集合中。
(3)判断每次取的边加入到最小生成树中之后是否会形成环,如果会形成环则不能将该边加入到最小生成树集合中。
(4)重复步骤2、3。直到满足 顶点数 - 边数量 = 1,则说明最小生成树构建完成。
具体步骤如下:
图结构如下
(1)根据边的权值对边进行排序处理得到结果如下图所示:
(1)取6-7构成的边加入到最小生成树集合中,显然不会构成环,则该边可以加入到最小生成树集合中
(2)取2-8构成的边加入到最小生成树集合中,显然不会构成环,则该边可以加入到最小生成树集合中
(3)取5-6构成的边加入到最小生成树集合中,显然不会构成环,则该边可以加入到最小生成树集合中
(4)取0-1构成的边加入到最小生成树集合中,显然不会构成环,则该边可以加入到最小生成树集合中
(5)取2-5构成的边加入到最小生成树集合中,显然不会构成环,则该边可以加入到最小生成树集合中
(6)取6-8构成的边加入到最小生成树集合中,此时构成环路,则不能将该边加入到最小生成树集合中
(7)取7-8构成的边加入到最小生成树集合中,此时构成环路,则不能将该边加入到最小生成树集合中
(8)取2-3构成的边加入到最小生成树集合中,显然不会构成环,则该边可以加入到最小生成树集合中
(9)取0-7构成的边加入到最小生成树集合中,显然不会构成环,则该边可以加入到最小生成树集合中
(10)取1-2构成的边加入到最小生成树集合中,此时构成环路,则不能将该边加入到最小生成树集合中
(11)取3-4构成的边加入到最小生成树集合中,显然不会构成环,则该边可以加入到最小生成树集合中
此时最小生成树集合中边的数量为8条,顶点个数为9,满足顶点数 - 边数 = 1,所以已经找到了构成最小生成树的边。
代码实现
代码中需要用到并查集来检测环路。如果能构成最小生成树则输出最小生成树的边的权值之和否则输出-1。
//并查集找根节点
int find(const vector<int>& parent, int x){
while(parent[x] != x){
x = parent[x];
}
return x;
}
//合并
void merge(vector<int>& parent, int x, int y){
int x_root = find(parent, x);
int y_root = find(parent, y);
parent[x_root] = y_root;
}
//仿函数
class mycompare{
public:
bool operator()(const vector<int>& v1, const vector<int>& v2){
return v1[2] < v2[2];
}
};
int minTree(int n, vector<vector<int>>& connections) {
//n表示顶点数
//conections = [[1,2,5],[1,3,6],[2,3,1]] 表示1-2边权值为5,1-3边权值为6,2-3边权值为1
//顶点序号从1开始
vector<int> parent(n + 1, 0);
int count = 0;//统计边的数量
for(int i = 1; i < parent.size(); ++i){
parent[i] = i;
}
int res = 0;
sort(connections.begin(), connections.end(), mycompare());
for(int i = 0; i < connections.size(); ++i){
if(find(parent, connections[i][0]) != find(parent, connections[i][1])){
merge(parent, connections[i][0], connections[i][1]);
res += connections[i][2];
count++;
}
}
return (count == n - 1 ? res : -1);
}