# include<iostream>
# include<cstring>
# define inf 0x3f3f3f3f
using namespace std;
const int maxn=100+5;
typedef struct node{
int adj; //顶点之间的权重
}node;
typedef struct graph{
int vertex[maxn];
node vertexs[maxn][maxn];//邻接矩阵
int vertexnum;
int edgenum;
}graph;
bool vis[maxn][maxn];
int pre[maxn];
int minsum;
int find(graph g,int i) //寻找对应顶点的索引
{
for(int j=0;j<g.vertexnum;j++)
if(g.vertex[j]==i)
return j;
return -1;
}
void init(graph &g) //初始化图
{
cin>>g.vertexnum>>g.edgenum;
for(int i=0;i<g.vertexnum;i++)
cin>>g.vertex[i];
for(int i=0;i<g.vertexnum;i++)
for(int j=0;j<g.vertexnum;j++)
g.vertexs[i][j].adj=inf;
for(int i=0;i<g.edgenum;i++)
{
int u,v,w;
cin>>u>>v>>w;
int index_u=find(g,u);
int index_v=find(g,v);
if(index_u==-1||index_v==-1)
{
cout<<"不存在该节点"<<endl;
continue;
}
g.vertexs[index_u][index_v].adj=w;
g.vertexs[index_v][index_u].adj=w;
}
}
void makeset(int x)
{
pre[x]=x;
}
int findset(int x)
{
if(pre[x]==x)
return pre[x];
else return pre[x]=findset(pre[x]);
}
bool link(int x,int y) //如果不构成回路,就合并,并返回true,反之返回false
{
int xx=findset(x);
int yy=findset(y);
if(xx!=yy)
{
pre[xx]=yy;
return true;
}
return false;
}
void mst_kruskal(graph g)
{
for(int i=0;i<g.vertexnum;i++)
makeset(i);
int index_v,index_u,cnt;
cnt=0; //边的初始个数
while(1)
{
int min_edge=inf;
if(cnt==g.vertexnum-1)//抽取完顶点数-1条边,结束循环
break;
for(int j=0;j<g.vertexnum;j++)
{
for(int w=0;w<g.vertexnum;w++)
{
if(j>w&&!vis[j][w]&&min_edge>g.vertexs[j][w].adj) //只访问邻接矩阵的上三角,且访问没有访问过的
{
min_edge=g.vertexs[j][w].adj;
index_v=j;
index_u=w;
}
}
}
vis[index_v][index_u]=true; //标记已访问
if(link(index_v,index_u)) //判断是否构成回路,若构不成回路,再将顶点并入最小生成树的顶点集中
{
cout<<"(v"<<g.vertex[index_u]<<",V"<<g.vertex[index_v]<<") ";
cnt++;
minsum+=min_edge;
}
}
cout<<minsum<<endl;
}
int main()
{
graph g;
init(g);
memset(vis,0,sizeof(vis));
mst_kruskal(g);
return 0;
}