/*利用Kruskal算法求无向网的最小生成树,并输出依次选择的各边及最终求得的最小生成树的权*/
/*输入:顶点个数n和边数m,然后输入m条边的数据u、v、w,分别表示这条边的两个顶点和权值*/
#include<stdio.h>
#include<stdlib.h>
#define MAXN 50
#define MAXM 50
struct edge{
int u,v,w; //边的顶点、权值
}edges[MAXM]; //边的数组
int parent[MAXN];
int m,n;
int i,j;
//初始化
void UFset(){
for( i=0; i<=n; i++ )
parent[i] = -1;
}
//查找并返回结点x所属集合的根结点
int Find( int x ){
int s; //查找位置
//一直查找到parent[s]为负数(此时的s即为根结点)为止
for( s=x; parent[s]>=0; s=parent[s] )
;
//优化方案—压缩路径,使后续的查找操作加速
while( s != x ){
int tmp = parent[x];
parent[x] = s;
x = tmp;
}
return s;
}
//将两个不同的集合进行合并
void Union( int R1, int R2 ){
//r1为R1的根结点,r2为R2的根结点
int r1 = Find(R1), r2 = Find(R2);
//tmp两个集合结点个数之和(负数)
int tmp = parent[r1] + parent[r2];
if( parent[r1] > parent[r2] ){
parent[r1] = r2;
parent[r2] = tmp;
}
else{
parent[r2] = r1;
parent[r1] = tmp;
}
}
//实现从小到大排序的比较函数
int cmp( const void *a, const void *b){
edge aa = *( const edge * ) a;
edge bb = *( const edge * ) b;
return aa.w - bb.w;
}
//Kruskal算法
void Kruskal(){
int sum_weight = 0; //生成树的权值
int num = 0; //已选用边的数目
UFset();
for( i=0; i<m; i++){
if( Find(edges[i].u) != Find(edges[i].v) ){
printf( "%d %d %d\n", edges[i].u, edges[i].v, edges[i].w );
sum_weight += edges[i].w;
num ++;
Union( edges[i].u, edges[i].v );
}
if( num >= n-1 )
break;
}
printf( "Weight of MST is %d\n", sum_weight );
}
int main(){
scanf("%d%d", &n, &m);
for(i=0; i<m; i++)
scanf( "%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w );
qsort( edges, m, sizeof(edges[0]), cmp ); //对边按从小到大排序
Kruskal();
return 0;
}