#include<stdio.h>const int Max=105;
int INF=99999;
bool vis[Max];
int dis[Max];//边集合
int map[Max][Max];
int N;voidsolve_data(){for(int i=1;i<=N;i++){
vis[i]=false;for(int j=1;j<=N;j++)if(i!=j) map[i][j]=INF;else map[i][j]=0;}}//输出调试查看 voidprin(){printf(" ");for(int i=0;i<N;i++)printf(" %c",'A'+i);printf("\n");for(int i=1;i<=N;i++){printf("%c:",'A'+i);for(int j=1;j<=N;j++){if(map[i][j]==INF)printf("%5d",-1);elseprintf("%5d",map[i][j]);}printf("\n");}}voidinit(){//使用%s读入能避免输入格式有误(多空格)
char str[105];for(int i=1;i<N;i++){scanf("%s",str);
int x=str[0]-'A'+1;
int K;scanf("%d",&K);while(K--){scanf("%s",str);
int y=str[0]-'A'+1;scanf("%d",&map[x][y]);
map[y][x]=map[x][y];}}}//最小生成树的起点:v voidprime(int v){
int ans=0;for(int i=1;i<=N;i++)
dis[i]=map[v][i];
vis[v]=true;for(int i=1;i<N;i++){//从边集合里找到最短边
int Min=INF,min_id;for(int j=1;j<=N;j++)if(!vis[j]&&dis[j]<=Min)
min_id=j,Min=dis[j];}//将最短边的点加入集合
vis[min_id]=true;
ans+=Min;//将加入集合的点遍历,加入其它边到集合中 for(int j=1;j<=N;j++)if(!vis[j]&&map[min_id][j]<dis[j])
dis[j]=map[min_id][j];}printf("%d\n",ans);}
int main(){while(scanf("%d",&N)!=EOF){if(N==0)break;solve_data();init();// prin();prime(1);}return0;}