#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<stdio.h>
#include<cstring>
using namespace std;
int const oo = 100000000;
int cost[103][103]; // 花费=边
int used[103][103]; // 表示这条边是否在生成树中
int father[103]; // 生成树中点的
int maxlen[103]; // 表示i点到根的路径上除了与根直接相连的边外,边权最大的边的边权。
int vis[103]; // 标记
int d[103]; // 求最小生成树时的离最小生成树的代价
int AnsMst; // 当前m度生成树的代价
int N, degree, lim; // degree表示最小限度,lim表示限度值
int g[103][103]; // 生成树中的儿子关系,正向表。
map<string, int> mat;
void MST(int S)
{ // 求从S点开始的最小生成树
while (1)
{
int K = -1;
for (int i = 1; i <= N; i++)
{
if (!vis[i] && d[i] != oo && (K == -1 || d[K] > d[i])) K = i;
}
if (K == -1) break;
vis[K] = 1;
AnsMst += d[K];
g[father[K]][++g[father[K]][0]] = K; // 记录儿子
if (d[K] != 0)
maxlen[K] = max(maxlen[father[K]], d[K]); // 算边权最大的边
used[K][father[K]] = used[father[K]][K] = 1; // 标记边在生成树中
for (int i = 1; i <= N; i++)
{
if (!vis[i] && cost[K][i] < d[i])
{
father[i] = K;
d[i] = cost[K][i];
}
}
}
}
void Build()
{
for (int i = 1; i <= N; i++) father[i] = i;
for (int i = 1; i <= N; i++) d[i] = oo;
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
used[i][j] = 0; // 所有的边都在生成树外
for (int i = 1; i <= N; i++) g[i][0] = 0; // 儿子树全为0
for (int i = 1; i <= N; i++) vis[i] = 0; // 标记清空
vis[1] = 1;
degree = 0;
maxlen[1] = -oo; // 根的maxlen为-oo
AnsMst = 0; // 开始时生成树的代价为0
while (1)
{
int K = -1;
for (int i = 1; i <= N; i++)
{
if (!vis[i] && (K == -1 || cost[1][i] < cost[1][K])) K = i; // 找一条边权最小的和跟相连的点开始做最小生成树
}
if (K == -1) break;
father[K] = 1; // father 为 1
maxlen[K] = -oo; // maxlen[k]=-oo
d[K] = 0;
degree++; // 联通分支个数加1
AnsMst += cost[1][K]; // 生成树代价增加
MST(K);
}
}
void Init()
{ // 开始的输入处理
mat.clear();
mat["Park"] = 1;
N = 1;
int M;
scanf("%d", &M);
for (int i = 1; i <= 30; i++)
{
for (int j = 1; j <= 30; j++) cost[i][j] = oo;
}
while (M--)
{
string a, b;
int c;
cin >> a >> b >> c;
int ida, idb;
if (mat.find(a) == mat.end()) mat[a] = ++N, ida = N;
else ida = mat[a];
if (mat.find(b) == mat.end()) mat[b] = ++N, idb = N;
else idb = mat[b];
cost[ida][idb] = cost[idb][ida] = c;
}
scanf("%d", &lim);
}
void Dfs(int nod, int fa)
{ // 更新维护maxlen和生成树中的父子关系
father[nod] = fa;
vis[nod]=1;
if (fa == 1) maxlen[nod] = -oo;
else maxlen[nod] = max(maxlen[fa], cost[nod][fa]);
for (int i = 1; i <= g[nod][0]; i++)
if (used[nod][g[nod][i]] && !vis[g[nod][i]]) Dfs(g[nod][i], nod);
}
void Solve()
{
if (degree > lim) cout << "Error" << endl;
int ans = AnsMst;
while (degree < lim)
{
degree++;
int id = -1;
int delta = oo;
for (int i = 1; i <= N; i++)
{ // 找代价最小的进行扩张
if (cost[1][i] != oo && !used[1][i])
{
if (id == -1)
{
id = i;
delta = cost[1][i] - maxlen[i];
continue;
}
if (cost[1][i] - maxlen[i] < delta)
{
id = i;
delta = cost[1][i] - maxlen[i];
}
}
}
if (id == -1) break;
AnsMst += delta; // 加上delta值
ans = min(ans, AnsMst);
int Len = maxlen[id];
used[1][id] = used[id][1] = 1; // 表示边被加入到当前的生成树中
g[1][++g[1][0]] = id; // 表示根多了一个儿子
while (cost[id][father[id]] != Len)
{ // 找最大的边,并顺路维护儿子关系
int fa = father[id];
g[id][++g[id][0]] = fa;
id = fa;
}
used[id][father[id]] = used[father[id]][id] = 0; // 标记边被删去
for (int i = 1; i <= N; i++) vis[i]=0;
Dfs(1, 1); // 维护
}
printf("Total miles driven: %d\n", ans);
}
int main() {
Init();
Build();
Solve();
return 0;
}