#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <memory.h>
using namespace std;
/*
* poj1639 AC
* K度最小生成树
* 1. 求出除去V0,其他每个森林的最小生成树(除去V0后,其他的点不一定都是连通的)。
* 2. 在每个森林中找出与V0距离最近的点,并与V0相连(此时即为一棵生成树,这棵
* 生成树的根结点为V0,即在与V0相连时,要修改前驱数组pre[])。
* 3. 循环 (度数 – 森林数)次,每次找到g[0][i] – MV[i]最小的i结点,其中MV[i]
* 为Vi到V0的路径上不与V0相连的边的最大权值。
* 如果g[0][i] – MV[i] >= 0说明已经是最优解了,退出。
* 否则加入g[0][i]这条边,删去Vi到V0的路径上不与V0相连的最大权值的边。
*
* 如何快速找到Vi到V0的路径上不与V0相连的边的最大权值?
* MV[x] = max(MV[father],edge[i].c) (edge[i]为x到father的边,递推可得)
* */
int N,S,T;
map<string,int> hash;
struct EDGE
{
int u,v,c,nm;
}edge[1000];
int head[25],next[1000],tot,goal;
struct cmp
{
bool operator()(const EDGE &t1,const EDGE &t2)
{
return t1.c>t2.c;
}
};
void addedge(int x,int y,int val)
{
edge[tot].u = x,edge[tot].v = y,edge[tot].c = val,edge[tot].nm = tot;
next[tot] = head[x],head[x] = tot++;
}
priority_queue<EDGE,vector<EDGE>,cmp> heap;
bool vis[25],sel_e[1000];
int solve(int x,int TT)
{
int E,nn,SUM;
while(!heap.empty()) heap.pop();
for(int i=head[x];i!=-1;i=next[i])
if(edge[i].v!=goal)
heap.push(edge[i]);
vis[x] = true,SUM = E = 0;
while(E<TT-1)
{
EDGE e = heap.top();
heap.pop();
if(vis[e.v]) continue;
sel_e[e.nm] = sel_e[e.nm^1] = true;
E++,SUM += e.c;
nn = e.v,vis[e.v] = true;
for(int i=head[nn];i!=-1;i=next[i])
if(edge[i].v!=goal && !vis[edge[i].v])
heap.push(edge[i]);
}
return SUM;
}
int col[25],C;
int dfs(int x)
{
col[x] = C;
int ss = 1;
for(int i=head[x];i!=-1;i=next[i])
if(edge[i].v!=goal && !col[edge[i].v])
ss += dfs(edge[i].v);
return ss;
}
int MV[25],ne[25];
void dfs_V(int x,int f)
{
for(int i=head[x];i!=-1;i=next[i])
if(sel_e[i] && edge[i].v!=f && edge[i].v!=goal)
{
if(MV[x]>edge[i].c)
{
MV[edge[i].v] = MV[x];
ne[edge[i].v] = ne[x];
}else
{
MV[edge[i].v] = edge[i].c;
ne[edge[i].v] = i;
}
dfs_V(edge[i].v,x);
}
}
int main()
{
scanf("%d",&N);
char st[20],en[20];
T = tot = goal = 0;
memset(head,-1,sizeof(head));
hash.clear();
for(int i=1;i<=N;i++)
{
int k;
scanf("%s%s%d",st,en,&k);
if(!hash.count(st)) hash[st] = ++T;
if(!hash.count(en)) hash[en] = ++T;
if(!goal)
{
if(!strcmp(st,"Park")) goal = hash[st];
if(!strcmp(en,"Park")) goal = hash[en];
}
addedge(hash[st],hash[en],k);
addedge(hash[en],hash[st],k);
}
scanf("%d",&S);
int ans = 0;
C = 0;
memset(vis,false,sizeof(vis));
memset(col,0,sizeof(col));
memset(sel_e,false,sizeof(sel_e));
for(int i=1;i<=T;i++)
if(i!=goal && !col[i])
++C,ans += solve(i,dfs(i));
int mi[25],me[25];
memset(mi,-1,sizeof(mi));
for(int i=head[goal];i!=-1;i=next[i])
{
int k = edge[i].v;
if(mi[col[k]]==-1 || edge[i].c<mi[col[k]])
{
mi[col[k]] = edge[i].c;
me[col[k]] = i;
}
}
for(int i=1;i<=C;i++)
ans += mi[i],sel_e[me[i]] = sel_e[me[i]^1] = true;
memset(MV,0,sizeof(MV));
for(int i=head[goal];i!=-1;i=next[i])
if(sel_e[i] && edge[i].v!=goal)
dfs_V(edge[i].v,goal);
for(int i=1;i<=S-C;i++)
{
int mm = 100000000,xx,ee,ww;
for(int j=head[goal];j!=-1;j=next[j])
if(!sel_e[j] && (mm==100000000 || mm>edge[j].c-MV[edge[j].v]))
{
mm = edge[j].c-MV[edge[j].v];
xx = edge[j].v,ee = j,ww = ne[edge[j].v];
}
if(mm>=0) break;
ans += mm;
sel_e[ee] = sel_e[ee^1] = true;
sel_e[ww] = sel_e[ww^1] = false;
MV[xx] = 0;
dfs_V(xx,goal);
}
printf("Total miles driven: %d\n",ans);
return 0;
}