最小生成树:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。目前用Kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
先说以下Kruskal算法:要让n个顶点的图连通,那么至少需要n-1条边,如果一个连通无向图不包含回路,那么就是一棵树,图的最小生成树就是让边的总长度之和最短,我们首先肯定从最小的开始选,依次按照边的顺序选择,直到用了n-1条边将整个图连通为止,即最小生成树。
Krustral算法代码如下:
#include <iostream>
using namespace std;
//边类
template<class DataType>
class Border
{
public:
DataType u; //第一个顶点
DataType v; //第二个顶点
DataType w; //边的权值
};
//算法核心类
template<class DataType>
class AirthmeticCure
{
public:
Border<DataType> *edgeObject; //边类对象数组
AirthmeticCure(int m, int n)
{
this->edgeObject = new Border<DataType>[n];
this->f = new int[m];
for (int i = 1; i <= m; i++) //并查集初始化
f[i] = i;
}
void quickSort(int first, int last)
{
int i, j;
Border<DataType> t;
if (first > last)
return;
i = first;
j = last;
while (i != j)
{
while (edgeObject[j].w >= edgeObject[first].w && i < j)
j--;
while (edgeObject[i].w <= edgeObject[first].w && i < j)
i++;
if (i < j)
{
t = edgeObject[i];
edgeObject[i] = edgeObject[j];
edgeObject[j] = t;
}
}
t = edgeObject[first];
edgeObject[first] = edgeObject[i];
edgeObject[i] = t;
quickSort(first, i - 1);
quickSort(i + 1, last);
return;
}
int findAncestor(int v)
{
if (f[v] == v)
return v;
else
{
f[v] = findAncestor(f[v]);
return f[v];
}
}
bool merge(int u, int v)
{
int t1, t2;
t1 = findAncestor(u);
t2 = findAncestor(v);
if (t1 != t2) //判读两个点是否在同一个集合中
{
f[t2] = t1;
return true;
}
return false;
}
private:
int *f; //并查集
};
int main()
{
int m, n, count = 0;
int sum = 0; //最小生成树的权值和
cout << "请输入顶点个数和边的个数:";
cin >> m >> n;
AirthmeticCure<int> *Q = new AirthmeticCure<int>(m, n);
for (int i = 1; i <= n; i++)
{
cin >> Q->edgeObject[i].u >> Q->edgeObject[i].v >> Q->edgeObject[i].w;
}
Q->quickSort(1, n);
for (int i = 1; i <= n; i++)
{
if (Q->merge(Q->edgeObject[i].u, Q->edgeObject[i].v))
{
count++;
sum = sum + Q->edgeObject[i].w;
}
if (count == m - 1)
break;
}
cout << sum << endl;
getchar();
getchar();
return 0;
}
运行结果如下: