// version 1 ,from hdu 1863
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10010;
const int inf=0x3f3f3f3f;
struct Edge
{
int p1;
int p2;
int value;
};
Edge edge[MAXN];
int father[110];
bool cmp(Edge a,Edge b){return a.value<b.value;}
int find(int a){return father[a]==a?a:father[a]=find(father[a]);}
void link(int a,int b)
{
int father1=find(a),father2=find(b);
if(father1!=father2)
father[father1]=father2;
}
int main()
{
int n,cont,m;
while(cin>>m>>n && m)
{
int sum=0,cont=0; //cont 判断生成树是否完成
int i;
for(i=0;i<=n;i++)
father[i]=i; //init
for(i=0;i<m;i++)
scanf("%d%d%d",&edge[i].p1,&edge[i].p2,&edge[i].value);
sort(edge+1,edge+m+1,cmp);
for(i=0;i<m && cont<n-1;i++)
{
// if(father[edge[i].p1]!=father[edge[i].p2]) //-<----判断用find()
if(find(edge[i].p1)!=find(edge[i].p2))
{
link(edge[i].p1,edge[i].p2);
sum+=edge[i].value;
cont++;
}
}
if(cont==n-1)
printf("%d\n",sum);
else
printf("?\n");
}
return 0;
}
// version 2
#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 110
#define M 5000
using namespace std;
int n, m, u[M], v[M], w[M], r[M], p[N];
bool cmp (int i, int j){return w[i]<w[j];}
int f (int x){return p[x]==x?x:p[x]=f(p[x]);}
int main ()
{
while (cin>>m>>n&&m)
{
for (int i=1; i<=n; ++i) p[i]=i;
for (int j=1; j<=m; ++j) r[j]=j;
for (int j=1; j<=m; ++j) cin>>u[j]>>v[j]>>w[j];
sort (r+1,r+1+m,cmp);
int ans=0, k=0;
for (int j=1; j<=m&&k<n-1; ++j)
{
int e=r[j];int x=f(u[e]),y=f(v[e]);
if (x!=y)ans+=w[e],++k,p[x]=y;
}
if (k<n-1)puts ("?");
else cout<<ans<<endl;
}
return 0;
}