1.寻找无向图的最小生成树,图的最小生成树其实就是通过一些删除边然后重构图使得这张图关于边或者点的权值和最小,比如HDU1233这是一道最小生成树的裸题。我们通过这个题来介绍kruskal算法。
2.其实图中只用两种元素,点和边。从这两种对象出发来解决这个问题就有两种算法,prime算法和kruskal算法。他们的思考的角度分别是从从点来思考,和从边来思考。
3.kruskal算法从边的角度来解决问题,使用贪心思想,首先,我们将整张图的边全部拿出来,然后重组。这样原来的图就会成为n个孤立的点(有的叫做n个森林)。然后我们对边集排序。
<1> 设一个有n个顶点的连通网络为G(V,E),最初先构造一个只有n个顶点,没有边的非连通图T={V,空},图中每个顶点自成一格连通分量。
<2> 在E中选择一条具有最小权植的边时,若该边的两个顶点落在不同的连通分量上,则将此边加入到T中;否则,即这条边的两个顶点落到同一连通分量上,则将此边舍去(此后永不选用这条边),重新选择一条权植最小的边。
<3> 如此重复下去,直到所有顶点在同一连通分量上为止。
其实就是并查集的使用。我们给出HDU1233的代码来作为kruskal的实现:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 1e4 + 5;
int father[maxn];
struct node
{
int u, v, val;
}edge[maxn];
bool cmp(node&a, node&b)
{
return a.val < b.val;
}
int Find(int x)
{
if (x == father[x])return father[x];
else return father[x] = Find(father[x]);
}
void join(int x, int y)
{
int fa = Find(x);
int fb = Find(y);
if (fa != fb) father[fb] = fa;
}
int kruskal(int n, int m)//n个点,m条边的完全连通图的克鲁斯卡尔算法
{
sort(edge, edge + m, cmp);
//初始化并查集
for (int i = 0; i <=n; i++)father[i] = i;
int ans = 0;
for (int i = 0; i < m; i++)
{
int fa = Find(edge[i].v);
int fb = Find(edge[i].u);
if (fa != fb)
{
join(fa, fb);
ans += edge[i].val;
}
}
return ans;
}
int main()
{
int n;
while (cin >> n && n)
{
int m = (n - 1)*n / 2;
for (int i = 0; i < m; i++)
{
cin >> edge[i].v >> edge[i].u >> edge[i].val;
}
cout << kruskal(n, m) << endl;
}
}