#include <iostream>
#include <sstream>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;

const int INF = (1<<28);
const int STR = (8*60);
const int LIM = (18*60);

class Train
{
public:
	int src,dst,dep,arv,cst;
	Train(int src, int dst, int dep, int arv, int cst)
		:src(src),dst(dst),dep(dep),arv(arv),cst(cst)
	{}
};

class State
{
public:
	int p,tm,cst,pvT, pvC;
	State(int p, int tm, int cst, int pvT, int pvC)
		:p(p),tm(tm),cst(cst),pvT(pvT),pvC(pvC)
	{}

	bool operator<(const State& s) const
	{
		if(cst != s.cst) return cst > s.cst;
		return tm > s.tm;
	}
};

typedef vector<Train> City;
typedef vector<vector<int> > Matrix;

int toMin(string s)
{
	stringstream ss(s);
	int h,m;
	char t;
	ss >> h >> t >> m;

	return h*60+m;
}

bool used[100][2005];

int dijkstra_go(int S, int T, int u, vector<City>& cities)
{
	priority_queue<State> q;

	for(int i=0; i<cities[S].size(); i++)
		q.push(State(cities[S][i].dst, cities[S][i].arv, cities[S][i].cst, i, S));

	memset(used, 0, sizeof(used));

	while(!q.empty()) {
		State s=q.top(); q.pop();
		if(used[s.pvC][s.pvT]) continue;
		used[s.pvC][s.pvT] = true;

		if(s.pvC == T && s.pvT == u) return s.cst-cities[s.pvC][s.pvT].cst;

		for(int i=0; i<cities[s.p].size(); i++) {
			Train t = cities[s.p][i];
			if(used[s.p][i]) continue;
			if(s.tm > t.dep) continue;
			if(i == u && s.p == T && s.tm + 30 > t.dep) continue;

			q.push(State(t.dst, t.arv, s.cst+t.cst, i, s.p));
		}
	}

	return INF;
}

int dijkstra_back(int S, int T, int u, vector<City>& cities)
{
	if(S == T) return 0;

	priority_queue<State> q;
	q.push(State(cities[S][u].dst, cities[S][u].arv, cities[S][u].cst, u, S));

	memset(used, 0, sizeof(used));

	while(!q.empty()) {
		State s = q.top(); q.pop();
		if(used[s.pvC][s.pvT]) continue;
		used[s.pvC][s.pvT] = true;

		if(s.p == T) return s.cst;

		for(int i=0; i<cities[s.p].size(); i++) {
			Train t = cities[s.p][i];
			if(used[s.p][i]) continue;
			if(s.tm > t.dep) continue;

			q.push(State(t.dst, t.arv, s.cst+t.cst, i, s.p));
		}
	}

	return INF;
}

int solve(int Hakodate, int Tokyo, vector<City>& cities)
{
	Matrix goKen(cities.size());
	for(int i=0; i<cities.size(); i++) {
		goKen[i].resize(cities[i].size());
		for(int j=0; j<cities[i].size(); j++) {
			goKen[i][j] = INF;
		}
	}

	Matrix backKen(goKen), goKeiko(goKen), backKeiko(goKen);

	for(int i=0; i<cities.size(); i++)
	for(int j=0; j<cities[i].size(); j++) {
		goKen[i][j] = dijkstra_go(Hakodate, i, j, cities);
		goKeiko[i][j] = dijkstra_go(Tokyo, i, j, cities);
		backKen[i][j] = dijkstra_back(i, Hakodate, j, cities);
		backKeiko[i][j] = dijkstra_back(i, Tokyo, j, cities);
	}

	int res = INF;
	for(int i=0; i<cities.size(); i++)
	for(int j=0; j<cities[i].size(); j++)
	for(int k=0; k<cities[i].size(); k++)
	{
		int g = (cities[i][j].dep < cities[i][k].dep ? j : k);
		res = min(res, goKeiko[i][g]+goKen[i][g]+backKeiko[i][j]+backKen[i][k]);
	}

	if(res == INF) res = 0;

	return res;
}

int main()
{
	int N;
	while(cin >> N, N) {
		
		int cnt=0;
		map<string, int> dic;
		vector<City> cities(N);
		for(int i=0; i<N; i++) {
			string src,dst,t,s;
			int c;
			cin >> src >> t >> dst >> s >> c;
			
			if(!dic.count(src)) dic[src] = cnt++;
			if(!dic.count(dst)) dic[dst] = cnt++;

			int l = toMin(t), r = toMin(s);
			if(l < STR || r < STR|| l > LIM || r > LIM) continue;

			cities[dic[src]].push_back(Train(dic[src], dic[dst], l, r, c));
		}

		int hako = dic["Hakodate"];
		int tokyo = dic["Tokyo"];

		cities[hako].push_back(Train(hako, hako, LIM, LIM, 0));
		cities[tokyo].push_back(Train(tokyo, tokyo, LIM, LIM, 0));

		cout << solve(hako, tokyo, cities) << endl;
	}

}

Measured memory_bytes: 1396