/*
1思路:最小生成树+kruskal
2注意把已经建好的合并
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 110
#define INF 0XFFFFFFF
int n , m , ans;
int father[MAXN];
int rank[MAXN];
struct Edge{
int x;
int y;
int value;
int state;
}e[10000];
bool cmp(Edge e1 , Edge e2){
return e1.value < e2.value;
}
void init_Set(){
for(int i = 1 ; i <= n ; i++){
father[i] = i;
rank[i] = 1;
}
}
int find_Set(int x){
int tmp = x;
while(father[tmp] != tmp)
tmp = father[tmp];
while(father[x] != tmp){
int tmp_x = father[x];
father[x] = tmp;
x = tmp_x;
}
return tmp;
}
void union_Set(int x , int y){
if(rank[x] >= rank[y]){
rank[x] += rank[y];
father[y] = x;
}
else{
rank[y] += rank[x];
father[x] = y;
}
}
void kruskal(){
sort(e , e+m , cmp);
ans = 0;
for(int i = 1 ; i <= m ; i++){
int root_x = find_Set(e[i].x);
int root_y = find_Set(e[i].y);
if(root_x != root_y){
if(!e[i].state)
ans += e[i].value;
union_Set(root_x , root_y);
}
}
printf("%d\n" , ans);
}
int main(){
//freopen("input.txt" , "r" , stdin);
while(scanf("%d" , &n) , n){
m = n*(n-1)/2;
init_Set();
for(int i = 1; i <= m ; i++){
scanf("%d%d%d%d" , &e[i].x , &e[i].y , &e[i].value , &e[i].state);
if(e[i].state)
union_Set(find_Set(e[i].x) , find_Set(e[i].y));
}
kruskal();
}
return 0;
}