#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std ;
const int maxe=5000 +5 ;
const int maxv=100 +5 ;
int n;
struct Edge{
int from,to;
int weight;
};
bool operator <(const Edge&E1,const Edge&E2)
{
return E1.weight<E2.weight;
}
Edge edges[maxe];
int vset[maxv];
int e;
int Getparent (int i)
{
if (i!=vset[i])
vset[i]=Getparent(vset[i]);
return vset[i];
}
void kruskal (int num)
{
int sum=0 ;
for (int j=1 ;j<=num;j++)
{
int p1=Getparent(edges[j].from);
int p2=Getparent(edges[j].to);
if (p1!=p2) {
sum+=edges[j].weight;
vset[p2]=p1;
e--;
}
}
cout <<sum<<endl ;
}
int main ()
{
while (scanf ("%d" ,&n)==1 &&n)
{
e=n-1 ;
for (int i=1 ;i<=n;i++)
vset[i]=i;
int num=(n*(n-1 ))/2 ;
for (int i=1 ;i<=num;i++)
{
int v1,v2,dist;
scanf ("%d%d%d" ,&v1,&v2,&dist);
edges[i].from=v1;
edges[i].to=v2;
edges[i].weight=dist;
}
sort(edges,edges+num+1 );
kruskal(num);
}
return 0 ;
}
prim:
//prim
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxv=100+6;
const int INF=1e6;
bool done[maxv]; //标志数组
int G[maxv][maxv];
int v,e;
struct node{
int cost,from,to;
node(int cost,int from,int to):cost(cost),from(from),to(to) {}
friend bool operator<( node N1, node N2)
{
return N1.cost>N2.cost;
}
};
int prim()
{
memset(done,false,sizeof(done));
done[1]=true;
priority_queue<node>pq; //权值 边的编号 小顶堆
while(!pq.empty()) pq.pop();
for(int i=2;i<=v;i++)
if(G[1][i]<INF) pq.push(node(G[1][i],1,i));
int t=0,sum=0;
while(true)
{
if(t==v-1) break;
node p=pq.top();
pq.pop();
if(done[p.from]&&!done[p.to])
{
done[p.from]=done[p.to]=true;
for(int i=1;i<=v;i++)
if(G[p.to][i]<INF&&!done[i]) pq.push(node(G[p.to][i],p.to,i));
sum+=p.cost;
t++;
}
}
return sum;
}
int main()
{
while(scanf("%d",&v)==1&&v)
{
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
G[i][j]=(i==j?0:INF);
e=v*(v-1)/2;
for(int i=0;i<e;i++)
{
int v1,v2,dist;
scanf("%d%d%d",&v1,&v2,&dist);
G[v1][v2]=G[v2][v1]=min(G[v1][v2],dist);
}
cout<<prim()<<endl;
}
return 0;
}