Problem:
Problem D: Long Distance Taxi

A taxi driver, Nakamura, was so delighted because he got a passenger who wanted to go to a
city thousands of kilometers away. However, he had a problem. As you may know, most taxis in
Japan run on liquefied petroleum gas (LPG) because it is cheaper than gasoline. There are more
than 50,000 gas stations in the country, but less than one percent of them sell LPG. Although
the LPG tank of his car was full, the tank capacity is limited and his car runs 10 kilometer per
liter, so he may not be able to get to the destination without filling the tank on the way. He
knew all the locations of LPG stations.
Your task is to write a program that finds the best way from the current location to the destination without running out of gas.

Input

The input consists of several datasets, and each dataset is in the following format.

N M cap

src dest

c1,1 c1,2 d1

c2,1 c2,2 d2

.

.

.

cN,1 cN,2 dN

s1

s2

.

.

.

sM

The first line of a dataset contains three integers (N, M, cap), where N is the number of roads
(1 ≤ N ≤ 3000),M is the number of LPG stations (1≤ M ≤ 300), and cap is the tank capacity
(1 ≤ cap ≤ 200) in liter. The next line contains the name of the current city (src) and the name
of the destination city (dest). The destination city is always different from the current city.
The following N lines describe roads that connect cities. The road i (1 ≤ i ≤ N) connects two
different cities ci,1 and ci,2 with an integer distance di (0 < di ≤ 2000) in kilometer, and he can
go from either city to the other. You can assume that no two different roads connect the same
pair of cities. The columns are separated by a single space. The next M lines (s1,s2,...,sM) indicate the names of the cities with LPG station.
You can assume that a city with LPG station has at least one road.

The name of a city has no more than 15 characters. Only English alphabet ('A' to 'Z' and 'a'
to 'z', case sensitive) is allowed for the name.

A line with three zeros terminates the input.

Output

For each dataset, output a line containing the length (in kilometer) of the shortest possible
journey from the current city to the destination city. If Nakamura cannot reach the destination,
output "-1" (without quotation marks). You must not output any other characters.
The actual tank capacity is usually a little bit larger than that on the specification sheet, so
you can assume that he can reach a city even when the remaining amount of the gas becomes
exactly zero. In addition, you can always fill the tank at the destination so you do not have to
worry about the return trip.

Sample Input

6 3 34
Tokyo Kyoto
Tokyo Niigata 335
Tokyo Shizuoka 174
Shizuoka Nagoya 176
Nagoya Kyoto 195
Toyama Niigata 215
Toyama Kyoto 296
Nagoya
Niigata
Toyama
6 3 30
Tokyo Kyoto
Tokyo Niigata 335
Tokyo Shizuoka 174
Shizuoka Nagoya 176
Nagoya Kyoto 195
Toyama Niigata 215
Toyama Kyoto 296
Nagoya
Niigata
Toyama
0 0 0

Output for the Sample Input

846
-1

Solution in JAVA (judge verdict: Memory Limit Exceeded)

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.PriorityQueue;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(true) {
			int n = sc.nextInt();
			int m = sc.nextInt();
			int cap = sc.nextInt();
			if (n == 0) {
				break;
			}
			int src = sc.next().hashCode();
			int dest = sc.next().hashCode();
			int[] list = new int[6000];
			int[][] a = new int[n][2];
			int[] d = new int[n];
			for(int i=0;i<n;i++) {
				a[i][0] = sc.next().hashCode();
				a[i][1] = sc.next().hashCode();
				d[i] = sc.nextInt();
			}
			for(int i=0;i<n;i++) {
				for(int j=0;j<2;j++) {
					add(list, a[i][j]);
				}
			}
			int ss = map(list, src);
			int gg = map(list, dest);
			int lvl = size(list);
			Graph g1 = new Graph(lvl);
			Graph g2 = new Graph(m+3);
			for(int i=0;i<n;i++) {
				g1.addBidirectionalEdge(map(list,a[i][0]), map(list,a[i][1]), d[i]);
			}
			int[] s = new int[m];
			for(int i=0;i<m;i++) {
				s[i] = map(list, sc.next().hashCode());
			}
			for(int i=0;i<m;i++) {
				int[] dist = g1.minDistDijkstra(s[i]);
				for(int j=0;j<m;j++) {
					if (i == j) {
						continue;
					}
					if (dist[j] <= cap * 10) {
						g2.addBidirectionalEdge(i, j, dist[j]);
					}
				}
				if (dist[ss] <= cap * 10) {
					g2.addBidirectionalEdge(i, m, dist[ss]);
				}
				if (dist[gg] <= cap * 10) {
					g2.addBidirectionalEdge(i, m+1, dist[gg]);
				}
			}
			int ans = g2.minDistDijkstra(m)[m+1];
			System.out.println(ans >= Graph.INF ? -1 : ans);
		}
	}

	public static void add(int[] l,int x) {
		int n = l.length;
		for(int i=0;i<n;i++) {
			if (l[i] == x) {
				break;
			}
			if (l[i] == 0) {
				l[i] = x;
				break;
			}
		}
	}
	public static int map(int[] l,int x) {
		int n = l.length;
		for(int i=0;i<n;i++) {
			if (l[i] == x) {
				return i;
			}
		}
		return -1;
	}

	public static int size(int[] l) {
		int n = l.length;
		for(int i=0;i<n;i++) {
			if (l[i] == 0) {
				return i;
			}
		}
		return n;
	}

}

class Graph {
	public static final int INF = 1<<29;
	int n;
	ArrayList<Edge>[] graph;

	@SuppressWarnings("unchecked")
	public Graph(int n) {
		this.n = n;
		this.graph = new ArrayList[n];
		for(int i=0;i<n;i++) {
			graph[i] = new ArrayList<Edge>();
		}
	}

	public void addBidirectionalEdge(int from,int to,int cost) {
		addEdge(from,to,cost);
		addEdge(to,from,cost);
	}
	public void addEdge(int from,int to,int cost) {
		graph[from].add(new Edge(to, cost));
	}

	//dijkstra O(ElogV)
	public int[] minDistDijkstra(int s) {
		int[] dist = new int[n];
		Arrays.fill(dist, INF);
		dist[s] = 0;
		PriorityQueue<Node> q = new PriorityQueue<Node>();
		q.offer(new Node(0, s));
		while(!q.isEmpty()) {
			Node node = q.poll();
			int v = node.id;
			if (dist[v] < node.dist) {
				continue;
			}
			for(Edge e:graph[v]) {
				if (dist[e.to] > dist[v] + e.cost) {
					dist[e.to] = dist[v] + e.cost;
					q.add(new Node(dist[e.to], e.to));
				}
			}
		}
		return dist;
	}

	//O(E) all cost is 0 or 1
	public int[] minDistQueue(int s) {
		int[] d = new int[n];
		Arrays.fill(d, INF);
		ArrayDeque<Integer> q = new ArrayDeque<Integer>();
		q.add(s);
		d[s] = 0;
		while(!q.isEmpty()) {
			int v = q.pollFirst();
			for(Edge e:graph[v]) {
				int u = e.to;
				if (d[v] + e.cost < d[u]) {
					d[u] = d[v] + e.cost;
					if (e.cost == 0) {
						q.addFirst(u);
					}else{
						q.addLast(u);
					}
				}
			}
		}
		return d;
	}

	//topologicalSort O(V+E)
	public ArrayList<Integer> topologicalSort() {
		ArrayList<Integer> order = new ArrayList<Integer>();
		int[] col = new int[n];
		for(int u=0;u<n;u++) {
			if (col[u] == 0 && !visitTS(order, col, u)) {
				return null;
			}
		}
		Collections.reverse(order);
		return order;
	}
	private boolean visitTS(ArrayList<Integer> order,int[] col ,int v) {
		col[v] = 1;
		for(Edge e:graph[v]) {
			if (col[e.to] == 2) {
				continue;
			}
			if (col[e.to] == 1) {
				return false;
			}
			if (!visitTS(order, col, e.to)) {
				return false;
			}
		}
		order.add(v);
		col[v] = 2;
		return true;
	}

	//longest Path in DAG
	public ArrayList<Integer> longestPathInDAG(int s,int g) {
		int[] dist = new int[n];
		int[] bef = new int[n];
		Arrays.fill(dist, -INF);
		Arrays.fill(bef, -1);
		ArrayList<Integer> order = topologicalSort();
		if (order == null) {
			return null;
		}
		dist[s] = 0;
		for(int i=0;i<n;i++) {
			int u = order.get(i);
			for(Edge e:graph[u]) {
				int v = e.to;
				if (dist[v] < dist[u] + e.cost) {
					dist[v] = dist[u] + e.cost;
					bef[v] = u;
				}
			}
		}
		ArrayList<Integer> path = new ArrayList<Integer>();
		int now = g;
		while(true) {
			path.add(now);
			if (bef[now] != -1) {
				now = bef[now];
				if (now == s) {
					break;
				}
			}else{
				return null;
			}
		}
		path.add(now);
		Collections.reverse(path);
		return path;
	}
	public int longestPathLengthInDAG() {
		int[] dist = new int[n];
		Arrays.fill(dist, 0);
		ArrayList<Integer> order = topologicalSort();
		if (order == null) {
			return -1;
		}
		int max = 0;
		for(int i=0;i<n;i++) {
			int u = order.get(i);
			for(Edge e:graph[u]) {
				int v = e.to;
				if (dist[v] < dist[u] + e.cost) {
					dist[v] = dist[u] + e.cost;
					max = Math.max(max,dist[v]);
				}
			}
		}
		return max;
	}

	public ArrayList<ArrayList<Integer>> stronglyConnectedComponents() {
		ArrayList<ArrayList<Integer>> scc = new ArrayList<ArrayList<Integer>>();
		int[] num = new int[n];
		int[] low = new int[n];
		ArrayDeque<Integer> s = new ArrayDeque<Integer>();
		boolean[] inS = new boolean[n];
		int time = 0;
		for(int u=0;u<n;u++) {
			if (num[u] == 0) {
				visitSCC(u,scc,s,inS,low,num,time);
			}
		}
		return scc;
	}
	private void visitSCC(int v, ArrayList<ArrayList<Integer>> scc,
			ArrayDeque<Integer> s, boolean[] inS, int[] low, int[] num, int time) {
		low[v] = num[v] = ++time;
		s.push(v);
		inS[v] = true;
		for(Edge e:graph[v]) {
			int w = e.to;
			if (num[w] == 0) {
				visitSCC(w,scc,s,inS,low,num,time);
				low[v] = Math.min(low[v],low[w]);
			}else if (inS[w]) {
				low[v] = Math.min(low[v],num[w]);
			}
		}
		if (low[v] == num[v]) {
			ArrayList<Integer> scc1 = new ArrayList<Integer>();
			while(true) {
				int w = s.poll();
				inS[w] = false;
				scc1.add(w);
				if (v == w) {
					break;
				}
			}
			scc.add(scc1);
		}
	}

	//dont' remove multiple edge
	public Graph noSCCGraph(int[] map) {
		ArrayList<ArrayList<Integer>> scc = stronglyConnectedComponents();
		int m = scc.size();
		for(int i=0;i<m;i++) {
			ArrayList<Integer> l = scc.get(i);
			for(int v: l) {
				map[v] = i;
			}
		}
		Graph h = new Graph(m);
		for(int u=0;u<n;u++) {
			for(Edge e:graph[u]) {
				h.addEdge(map[u], map[e.to], e.cost);
			}
		}
		return h;
	}

	class Edge {
		int to;
		int cost;
		public Edge(int to,int cost) {
			this.to = to;
			this.cost = cost;
		}
	}
	class Node implements Comparable<Node>{
		int dist;
		int id;
		public Node(int dist,int i) {
			this.dist = dist;
			this.id = i;
		}
		public int compareTo(Node o) {
			return (this.dist < o.dist) ? -1 : ((this.dist == o.dist) ? 0 : 1);
		}
	}
}