算法分类:
贪心
算法原理:
先从对权以非降序排列着手。接着从由图的顶点组成而不包含边的森林(V,T)开始,重复下面的这一步,知道(V,T)被换成一棵树:
设(V,T)是到现在为止构建的森林,e∈(E-T)为当前考虑的边,如果把e加到T中不生成一个回路,那么将e加入到T,否则丢弃e。
这个处理在恰好加完n-1条边后结束。
概括如下:
1. 对G的边以非降序权重排列;
2. 对于排序表中的每条边,如果现在把它放入T不会形成回路的话,则把它加入到生成树T中;否则将它丢弃。
算法时间复杂度:
O(mlogm) m为边数
则m可以像n(n-1)/2那么大,则时间复杂度为O(n平方logn)
m也可以是平面的,那么时间复杂度为O(nlogn)
代码实现:(HDU1233)
/* HDU 1233 还是畅通工程
* 最小生成树 Kruskal
*/
#include <iostream>
#include <algorithm>
using namespace std;
const int SIZE = 105;
int root[SIZE];
struct _Edge {
int s, e, v;
}E[SIZE*(SIZE-1)/2];
bool cmp(const _Edge a, const _Edge b) {
return a.v < b.v;
}
int find(int x) {
int y = x;
while (root[y] != y) {
y = root[y];
}
return y;
};
int Kruskal(int N, int index) {
for (int i = 1; i <= N; ++ i)
root[i] = i;
int EDGE = 0, value = 0;
sort(E, E+index, cmp);
for (int i = 0; i < index && EDGE < N-1; ++ i) {
int f1 = find(E[i].s);
int f2 = find(E[i].e);
if (f1 != f2) {
root[f1] = f2;
value += E[i].v;
++ EDGE;
}
}
return value;
};
int main()
{
int N, s, e, v;
while (scanf("%d",&N)!=EOF, N) {
int len = N*(N-1)/2;
for (int i = 0; i < len; ++ i) {
scanf("%d%d%d",&s,&e,&v);
E[i].s = s;
E[i].e = e;
E[i].v = v;
}
int result = Kruskal(N, len);
printf("%d\n",result);
}
}