#include<stdio.h>
#include<string.h>
const int INF = 0x3f3f3f;
const int N = 105;
/*
简述prim过程
1.初始化最小生成树(最开始只有一个点,这个点可以是任意一个点)
2.维护最小生成树,每次选取离原有生成树最近的点,并加入最小生成树,
然后用这个点更新其他点到最小生成树的距离(类似于松弛)
*/
int n,m;
int data[N][N];
int prim();
int main()
{
scanf("%d %d", &n, &m); //点的数目和边得数目
for(int i =0; i <=n;i++) //初始化为一个极大值。(若两点之间没有连通,则用极大值替代)
for(int j = 0; j <=n; j++)
data[i][j] = INF;
for(int i =0; i < m; i++) //prim用邻接矩阵建图(所以适用于稠密图)
{
int x,y,w;
scanf("%d %d %d",&x, &y,&w);
data[x][y] = data[y][x] = w;
}
int result = prim();
printf("%d\n",result);
return 0;
}
int prim()
{
int dis[N],sum = 0;
int mark[N] = {0};
int edge[N]; //edge[i] = j表示在生成树中,j的父亲是i;
mark[1] = 1;
for(int i = 1; i <= n; i++)
{
dis[i] = data[1][i];
edge[i] = 1; //初始化edge,刚开始生成树中只有点1,所以其他的点都指向点1
}
for(int i =1; i < n; i++)
{
int min_val = INF;
int min_id;
for(int j = 1; j <=n; j++)
{
if(mark[j] == 0 && min_val > dis[j])
{
min_val = dis[j];
min_id = j;
}
}
sum += min_val;
mark[min_id] = 1;
if(data[edge[min_id]][min_id] > 0)
printf("%d %d\n",edge[min_id],min_id);
for(int k =1; k <= n; k++)
{
if(mark[k] == 0 && dis[k] > data[min_id][k])
{
dis[k] = data[min_id][k];
edge[k] = min_id; //更新min_id的儿子;
}
}
}
return sum;
}