Problem:
Princess in Danger

お姫様の危機

English text is not available in this practice contest.

ある貧乏な国のおてんばで勇敢なお姫様が，政略結婚のため別の国に嫁ぐことになった．ところが，お姫様を亡き者としようとしている悪漢に嫁ぎ先への道中で襲われお姫様が大けがをしてしまい，近くの病院に搬送された．ところが，悪漢はお姫様は確実に亡き者とするため特殊な毒を使っていた．そのため，お姫様を助けるには本国から特別な薬と冷凍された肉親の血液を大急ぎで運ばなければならなくなった．

この血液は冷凍状態で輸送されるのだが，鮮度を保つため，前回の冷凍から最大 M 分以内に血液冷凍施設で再冷凍しなければならない．しかし，冷凍施設が設置されている場所は数カ所しかない．

血液は，十分に冷凍した状態から，再冷凍なしで M 分の間無事である．再冷凍しなくてすむ残り時間が S 分のときに，T 分間冷凍しないで輸送した場合，再冷凍しなくてすむ残り時間は S - T 分となる．再冷凍しなくてすむ残り時間は，再冷凍することにより，最大 M 分まで回復する．血液の再冷凍にかかる時間は，どれだけ冷凍するかに依存する．血液を冷凍施設で，1分冷凍するごとに再冷凍しなくてすむ残り時間は1分回復する．

本国の首都を出発する時点の，血液を再冷凍しなくてすむ残り時間はM分である．

お姫様の従者であるあなたは，大切な主君の命を救うため，本国の首都からお姫様が搬送された病院まで血液の鮮度を保ったまま輸送するための経路を計算しなければならない．そう，あなたの使命は，本国の首都からその病院への最短経路を割り出し，その最短時間を求めることである．

Input

入力は，複数のデータセットより構成される．各データセットの最初の行には，6 つの非負の整数 N(2 ≦ N ≦ 100)，M(1 ≦ M ≦ 100)，L(0 ≦ L ≦ N - 2)，K，A(0 ≦ A ＜ N)，H(0 ≦ H ＜ N) が与えられる．これらはそれぞれ，町の数，再冷凍を行うまでの制限時間，冷凍施設のある町の数，町と町を直接結ぶ道路の数，本国の首都を表す番号，お姫様が搬送された病院のある町の番号を表す．本国の首都とお姫様が搬送された病院は，異なる町である．なお，町には 0 〜 N-1 までの番号がそれぞれ割り当てられているものとする．続く行には，L 個の非負の整数が 1 つの空白で区切られて与えられる．これらは，冷凍施設がある町の番号を表す．なお，本国の首都とお姫様が搬送された病院はこのリストには含まれないが，冷凍施設があるものと考えて良い．続く K 行では，町と町を結ぶ道路の情報が与えられる．その第 i 行目では，3 つの非負の整数 X ，Y ，T が 1 つの空白で区切られて与えられ，これは町 X と町 Y を直接結ぶ道があり，移動には時間 T を要するということを表す．なお，この道は双方向に通行可能である．また，町Xと町Yを直接結ぶ道は高々一つしか無い．

入力は N = M = L = K = A = H = 0 の時に終了し，これはデータセットに含まれない．

Output

各データセットについて，鮮度を保ったまま血液を届けることができる最短時間を出力せよ．もし届けることができない場合には "Help!" と出力せよ．

Sample Input

2 1 0 1 0 1
0 1 2
3 1 1 2 0 1
2
0 2 1
1 2 1
3 2 1 2 0 1
2
0 2 1
1 2 1
4 4 1 4 1 3
2
0 1 2
1 2 4
0 2 1
3 0 3
5 3 2 6 0 3
1 2
2 1 2
1 0 1
3 4 1
2 4 1
4 1 2
2 0 2
5 4 2 6 0 3
1 2
4 2 4
2 1 2
4 3 1
0 1 5
1 4 2
2 0 3
0 0 0 0 0 0

Output for the Sample Input

Help!
3
2
10
5
12

Solution in JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

import static java.lang.Integer.parseInt;

/**
 * Princess in Danger
 */
public class Main {

	static final int INF = 1 << 29;

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String line;
		StringTokenizer st;

		while ((line = br.readLine()) != null && !line.isEmpty()) {

			st = new StringTokenizer(line);

			int N, M, _L, K, A, H;
			boolean[] L;
			Map<Integer, List<Edge>> G;
			int[][] D; //????????????: [????±???????][?????????????????????????????????]

			N = parseInt(st.nextToken());   //N: ????????°
			M = parseInt(st.nextToken());   //M: ???????????????????????§?????¶?????????
			_L = parseInt(st.nextToken());  //_L: ??????????¨??????????????????°
			K = parseInt(st.nextToken());   //K: ?????¨????????´??\?????¶???????????°
			A = parseInt(st.nextToken());   //A: ??¬?????????????????¨?????????
			H = parseInt(st.nextToken());   //H: ????§??§??????¬?????????????????¢?????????????????????
			if ((N | M | _L | K | A | H) == 0) break;

			//
			L = new boolean[N];
			L[A] = L[H] = true;

			if (_L > 0) {
				st = new StringTokenizer(br.readLine());
				for (int i = 0; i < _L; i++) {
					L[parseInt(st.nextToken())] = true;
				}
			}

			//
			G = new HashMap<>();

			for (int i = 0; i < N; i++) G.put(i, new ArrayList<>());

			for (int i = 0; i < K; i++) {
				st = new StringTokenizer(br.readLine());
				if (!st.hasMoreTokens()) {
					st = new StringTokenizer(br.readLine());
				}
				int X, Y, T;
				X = parseInt(st.nextToken());
				Y = parseInt(st.nextToken());
				T = parseInt(st.nextToken());
				G.get(X).add(new Edge(Y, T));
				G.get(Y).add(new Edge(X, T));
			}

			//
			D = new int[N][M + 1];
			for (int i = 0; i < N; i++) Arrays.fill(D[i], INF);
			D[A][M] = 0;

			Queue<P> pq = new PriorityQueue<>();
			pq.offer(new P(A, 0, M));

			//
			while (!pq.isEmpty()) {

				P p = pq.poll();

				if (D[p.to][p.stime] < p.ctime) continue;

				int v, s;
				v = p.to;
				s = p.stime;

				if (v == H) break;

				for (Edge e : G.get(v)) {
					if (M >= e.time) {
						int m = (L[v] ? M - s : 0);
						for (int i = 0; i <= m; i++) {
							int ctime, stime;
							ctime = D[v][s] + e.time + i;
							stime = (s + i) - e.time;
							if (stime >= 0
									&& D[e.to][stime] > ctime) {
								D[e.to][stime] = ctime;
								pq.offer(new P(e.to, ctime, stime));
							}
						}
					}
				}
			}

			//
			int ans = INF;

			for (int i = 0; i <= M; i++) ans = Math.min(ans, D[H][i]);

			System.out.println(ans != INF ? ans : "Help!");
		}
	}
}

class Edge {

	int to, time;

	public Edge(int to, int time) {
		this.to = to;
		this.time = time;
	}
}

class P implements Comparable<P> {

	int to, ctime, stime;

	public P(int to, int ctime, int stime) {
		this.to = to;
		this.ctime = ctime;
		this.stime = stime;
	}

	@Override
	public int compareTo(P o) {
		return Integer.compare(ctime, o.ctime);
	}
}