#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int S[101];
struct Edge{
    int a,b;
    int cost;
}edge[10001];
bool cmp(Edge e1,Edge e2){
    return e1.cost<e2.cost;
}//排序的比较函数
void Initial(int n){
    int i;
    for(i=1;i<=n;i++)S[i]=-1;
}//对父节点的初始化
int find(int x){
    while(S[x]>=0)x=S[x];
    return x;
}//找到父节点
void Union(int root1,int root2){
    if(root1==root2)return;
    S[root1]=root2;
}//加入并查集
int main() {
    int n,m,i,price,res;
    while (cin >> n>>m&&n!=0) { // 注意 while 处理多个 case
        Initial(m);
        price=0;res=0;
        for(i=0;i<n;i++){
            cin>>edge[i].a>>edge[i].b>>edge[i].cost;
        }
        sort(edge,edge+n,cmp);//按照代价从小到大对道路进行排序
        for(i=0;i<n;i++){
            if(find(edge[i].a)!=find(edge[i].b)){
                price+=edge[i].cost;
                Union(find(edge[i].a),find(edge[i].b));//当选定该节点为边时加入并查集
            }
        }
        for(i=1;i<=m;i++){
            if(S[i]==-1)res++;//判断连通图数目
        }
        if(res!=1)cout<<'?';//如果有一个以上连通图说明不能实现畅通
        else cout<<price;
        cout<<endl;
    }
}
// 64 位输出请用 printf("%lld")