版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Murdock_C/article/details/49561049
克鲁斯卡尔(Kruskal)算法(只与边相关)
算法描述:克鲁斯卡尔算法需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。
算法过程:
1.将图各边按照权值进行升序排序
2.将图遍历一次,找出权值最小的边,(条件:此次找出的边不能和已加入最小生成树集合的边构成环),若符合条件,则加入最小生成树的集合中。不符合条件则继续遍历图,寻找下一个最小权值的边。
3.递归重复步骤1,直到找出n-1条边为止(设图有n个结点,则最小生成树的边数应为n-1条),算法结束。得到的就是此图的最小生成树。
克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。而prime算法因为只与顶点有关,所以适合求稠密图的最小生成树。
具体算法如下:有用到并查集的算法思想,具体可以自己百度“并查集”了解
#include <iostream>
#include <algorithm>
using namespace std;
struct edge //边结构,存储边的两个节点及边的长度
{
int start_point;
int end_point;
int length;
};
const int N = 100; //设置最多的节点数为100
edge Edge[N];
int pre[N]; //pre数组保存节点的根节点信息,初始化为本身
bool cmp(edge a, edge b) //排序函数的比较因子,按照边的长度、节点序号的升序排列
{
if (a.length == b.length)
{
if (a.start_point == b.start_point)
{
return a.end_point < b.end_point;
}
else
return a.start_point < b.start_point;
}
else
return a.length < b.length;
}
int find(int x) //查找节点x的根节点,并进行路径压缩,具体细节可以百度“并查集”
{
int r = x;
while (pre[r] != r)
{
r = pre[r];
}
int i = x;
int j;
while (i != r)
{
j = pre[i];
pre[i] = r;
i = j;
}
return r;
}
int main()
{
int n, m, i, j, k, v, w;
int s, e, length;
int sum = 0;
cin >> n; //输入边的数目
for (i=0; i<n; ++i) //初始化,存储边的信息,节点号我们按照从1开始
{
cin >> s >> e >> length;
Edge[i+1].start_point = s;
Edge[i+1].end_point = e;
Edge[i+1].length = length;
}
for (i=0; i<n; ++i)
{
pre[i+1] = i + 1; //初始化节点根节点信息
}
sort(Edge+1,Edge+n+1,cmp); //对边的信息按照长度升序排序
for (i=0; i<n; ++i) //遍历所有的边
{
k = Edge[i+1].start_point;
v = Edge[i+1].end_point;
k = find(k);
v = find(v);
if (k != v) ////查找这条边的两个节点是否位于同一个连通分支,若不是,则将该边加入进去,并将它们的根节点连通起来(pre[k] = v)
{
sum += Edge[i+1].length;
pre[k] = v;
cout << Edge[i+1].start_point << "->" << Edge[i+1].end_point << Edge[i].length << endl;
}
}
cout << sum << endl;
system("pause");
return 0;
}
如有错误,欢迎指出。