Problem:
Problem C: Seishun 18 Kippu

R大学のとある学生sirokurostoneはA津大学で行われる合宿に参加しようとしていた。
他のメンバーは新幹線を使用する予定なのだが、sirokurostoneは青春18切符を使って向かおうとしていた。
同じく青春18切符使いのとある2D好きな人物も合宿に参加しようとしていた。

どうせならと一緒に行こうと考えたsirokurostoneは途中の駅で2D好きな彼を拾って向かおうと考えた。
sirokurostoneはR大学を出る前に遅延状況を確認してすこしでも時間のかからないルートを通ってA津大学のある駅に着きたいと考えている。
sirokurostoneはルートが確定した後に2D好きな彼にもその情報を伝えるつもりである。
しかし、sirokurostoneは遅延状況を見てもどのルートを通れば早くA津大学のある駅に到着できるか分からず困っている。

そこで、あなたの仕事はsirokurostoneに代わって遅延状況からどれくらいでA津大学のある駅に着くのかを求めることである。

各駅間には、駅間の距離と遅延予想時間がある。
電車は動き始めてから40km/hを維持するものとする。
地点aと地点bの間の移動時間は、

距離/40+遅延予想時間

で求めることができる。
各駅での停車時間は無視してよいものとする。

Input

複数のデータセットの並びが入力として与えられる。
データセット数は50以下であることが保障されている。
各データセットは、次の形式をしている。

n m
s p g
a1 b1 d1 t1
...
ai bi di ti
...
am bm dm tm

整数n(3 ≤ n ≤ 500)とm(2 ≤ m ≤ 5000)は、それぞれ駅の数、各駅間の線路の数の合計を表す。
s、p、gは、それぞれsirokurostoneが乗る駅、2D好きな人物が乗る駅、A津大学がある駅の場所を示す文字列である。
s、p、gはそれぞれ違う文字列である。

続くm行は、駅間情報を表す。
ai、biは、線路がつなぐ駅を示す文字列である。
aiとbiは、双方向に行き来することができる。
aiとbiが一致することはない。
整数di(40 ≤ di ≤ 10000)は、aiとbiの距離を表す。
diは40の倍数であることが保証されている。
整数ti(0 ≤ ti ≤ 20)は、aiとbiの間の遅延予想時間を示す。

駅名を表す文字列は、全てアルファベットの小文字および大文字からなる20文字以下の文字列であらわされる。
駅と駅の間の線路は高々1本である。

入力の終わりは2つのゼロを含む行で表される。

Output

入力データセットごとに、A津大学がある駅への到達時間(単位:時間)を出力せよ。
sirokurostoneが乗る駅から2D好きな人が乗る駅までの経路と、2D好きな人物が乗る駅からA津大学がある駅の場所までの経路があることが保証されている。

Sample Input

4 4
A B G
A B 40 3
B C 80 0
A G 40 0
B G 80 0
5 6
Kusatsu Tokyo Aizu
Tokyo Nagoya 120 3
Kusatsu Nagoya 40 0
Kusatsu Kanazawa 40 0
Kanazawa Aizu 40 0
Tokyo Kanazawa 40 0
Tokyo Aizu 80 4
0 0

Output for Sample Input

5
4

Solution in C++11 (judge verdict: Accepted)

#include <queue>
#include <limits>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
struct edge {
	int to, cost;
	edge(int to_, int cost_) : to(to_), cost(cost_) {};
};
bool operator<(const edge& e1, const edge& e2) {
	return e1.cost < e2.cost;
}
template<class Type>
std::vector<Type> shortest_path(std::vector<std::vector<edge> > &G, int s) {
	std::priority_queue<edge> que; que.push(edge(s, 0));
	std::vector<Type> ret(G.size(), std::numeric_limits<Type>::max()); ret[s] = 0;
	while (!que.empty()) {
		edge u = que.top(); que.pop();
		for (edge e : G[u.to]) {
			if (ret[e.to] > ret[u.to] + e.cost) {
				ret[e.to] = ret[u.to] + e.cost;
				que.push(edge(e.to, -ret[e.to]));
			}
		}
	}
	return ret;
}
int n, m, d, e;
int main() {
	while (cin >> n >> m, n) {
		string s, t, g;
		cin >> s >> t >> g;
		vector<string> a(m), b(m), r; vector<int> x(m);
		for (int i = 0; i < m; i++) {
			cin >> a[i] >> b[i] >> d >> e;
			x[i] = d / 40 + e;
			r.push_back(a[i]);
			r.push_back(b[i]);
		}
		sort(r.begin(), r.end());
		r.erase(unique(r.begin(), r.end()), r.end());
		int sp = lower_bound(r.begin(), r.end(), s) - r.begin();
		int tp = lower_bound(r.begin(), r.end(), t) - r.begin();
		int gp = lower_bound(r.begin(), r.end(), g) - r.begin();
		vector<vector<edge> > G(n);
		for (int i = 0; i < m; i++) {
			int ptr1 = lower_bound(r.begin(), r.end(), a[i]) - r.begin();
			int ptr2 = lower_bound(r.begin(), r.end(), b[i]) - r.begin();
			G[ptr1].push_back(edge(ptr2, x[i]));
			G[ptr2].push_back(edge(ptr1, x[i]));
		}
		int w1 = shortest_path<int>(G, sp)[tp];
		int w2 = shortest_path<int>(G, tp)[gp];
		cout << w1 + w2 << endl;
	}
	return 0;
}