#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
const int MAXN = 205;
const int INF = 1000000;
int dis[MAXN];
int n;//结点数量
typedef pair<int,int> pii;
struct edge//建立边的结构体
{
int v; //v表示一条边的终点,w表示边的权重
int w;
edge(int vv,int ww)
{
v = vv;
w = ww;
}
};
int dijkstra(int st,int ed,vector<edge> G[])
{
priority_queue<pii,vector<pii >,greater<pii > > q; //优先队列是默认大元素先出队,所以要改成小元素先出队
for(int i = 0;i < n;++i)
dis[i] = (i == st ? 0 : INF);//初始化dis
q.push(make_pair(dis[st],st));//将起点插入队列,pair默认是优先处理first元素,故插入优先队列先弹出队列的优先级是依据dis[]大小
while(!q.empty())
{
pii u = q.top(); //每次都弹出最小值,再在这最小值基础上修改其它结点的最短距离,就是Dijkstra算法
q.pop();
int x = u.second;
if(u.first != dis[x]) continue;//可避免结点的重复拓展,提高优先队列处理速度。去掉这一句也不影响程序的正确性,只是更费时,也能通过sicily
//相当于Dijkstra算法对每个结点都会进行一次标号。 这里每一个元素出队都相当于处理一次已标号结点,如果出队的这个元素,他带的dis,和当前的dis不相同,证明这个结点是被处理过的
for(int i = 0;i < G[x].size();++i) //在邻接表中长度各不同,所以用size(),即vector做邻接表更方便
{
int y = G[x][i].v;
int w = G[x][i].w;
if(dis[y] > dis[x] + w)
{
dis[y] = dis[x] + w;
q.push(make_pair(dis[y],y));
}
}
}
if(dis[ed] == INF)
return -1;
else return dis[ed];
}
int main()
{
int t,w;
string u,v;
cin >> t;
while(t--)
{
n = 0;//初始化结点数目
int e;
cin >> e;
map<string,int> M; //把每个地址转化成相对应的唯一的数字
vector<edge> G[MAXN];//邻接表
for(int i = 0;i < e;++i)
{
cin >> u >> v >> w;//输入点1,点2, 权值
if(!M.count(u))
M.insert(make_pair(u,n++));
if(!M.count(v))
M.insert(make_pair(v,n++));//利用map关联容器为字符串型的边进行标号
edge E1(M[v],w);//初始化边,必须调换结点才能插入vector邻接表
edge E2(M[u],w);
G[M[u]].push_back(E1);//建立邻接表
G[M[v]].push_back(E2);
}
string st,ed;
cin >> st >> ed;
if(st == ed)
cout << 0 << endl;
else if(!M.count(st) || !M.count(ed))
cout << -1 << endl;
else
cout << dijkstra(M[st],M[ed],G) << endl;
}
return 0;
}