#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<math.h>
#include<queue>
#define MAXN 105
using namespace std;
int root[MAXN];
struct edge{//定义边结构体
int head;//边头
int tail;//边尾
int cost;//花费
friend bool operator< (const edge &e1,const edge &e2){ //定义比较函数
return e1.cost > e2.cost;// 此处 > 表示升序排序
}
};
priority_queue<edge> qn;//定义优先队列
int findroot(int index){//查找根节点
if(root[index] == -1)
return index;
else
return root[index] = findroot(root[index]);
}
int kruskal(){
int count;
edge ebuf;
count=0;
while(!qn.empty()){
ebuf = qn.top();
qn.pop();
int bufroot1 = findroot(ebuf.head);
int bufroot2 = findroot(ebuf.tail);
if(bufroot1 != bufroot2){//若根节点相同,说明两个点属于同一棵树,不做处理,不同则将其加入生成树中
root[bufroot1] = bufroot2;
count+=ebuf.cost;
}
}
return count;
}
int main(){
int i;
int n;
int u,v,cost,complete;
edge edgebuf;
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(scanf("%d",&n) && n!=0){
for(i=0;i<n;i++){
root[i]=-1;
}
for(i=0;i<n*(n-1)/2;i++){
scanf("%d %d %d %d",&u,&v,&cost,&complete);
if(complete){//判断是否已经建造,若是,将其边加入生成树
int bufroot1 = findroot(u-1);
int bufroot2 = findroot(v-1);
if(bufroot1 != bufroot2)
root[bufroot1] = bufroot2;
}else{//不是,加入队列,利用kruskal算法进行选择
edgebuf.head = u-1;
edgebuf.tail = v-1;
edgebuf.cost = cost;
qn.push(edgebuf);
}
}
printf("%d\n",kruskal());
}
return 0;
}