Problem:
自転車でダイエット

A さんは甘いものが大好きですが、最近は奥さんからダイエットするように言われています。ある日、A さんが自宅から市役所に出かけるとき、奥さんは自転車で行くことを勧めました。そこでA さんはしぶしぶ自転車に乗って出かけましたが、甘い物の好きな A さんは、途中にあるケーキ屋さんに立ち寄りケーキの食べ歩きをしようと思いつきました。

自転車をこげば走行距離に応じてカロリーが消費されますが、ケーキを食べればその分カロリーが摂取されます。正味の消費カロリーは、自転車をこいで消費したカロリーからケーキを食べて摂取したカロリーを引いた値になります。したがって、正味の消費カロリーが 0 より小さくなることもあります。

ケーキ屋さんでケーキを買ったら、 Aさんはその場でケーキを全部食べてしまいます。 Aさんがすべてのケーキ屋さんに立ち寄るとは限りませんが、ケーキ屋さんが存在する地点を通るときには、必ず立ち寄ってケーキを 1 つ買って食べるものとします。ただし、同じケーキ屋さんの前を何度も通るのはさすがに気がひけるので、各ケーキ屋さんに訪れられるのは 1 回だけとします。また、目的地の市役所をいったん通り過ぎてからケーキ屋さんに立ち寄り、その後で市役所に戻って用を済ませてもよいものとし、ケーキ屋さん以外は何度訪れても良いものとします。

A さんの自宅から市役所までの地図情報と、その途中にあるケーキ屋さんで食べられるケーキのカロリーの一覧、単位距離の走行による消費カロリーを入力とし、自宅を出発してから市役所に入るまでの正味の消費カロリーの最小値を出力するプログラムを作成してください。

地図には、A さんの自宅と市役所、ケーキ屋さんとランドマーク(目印)になる建物が書かれています。地図を表す入力データは、A さんの自宅、市役所、ケーキ屋さんとランドマークの各地点の間をつなぐ道があるとき、2 つの地点を表す記号とその間の距離からなる行を含みます。たとえば、5 番目のケーキ屋さんと 3 番目のランドマークの間の距離が 10 なら、入力データは以下のような行を含みます。

C5 L3 10

このようにケーキ屋さんには C、ランドマークには L を番号の前につけて表します。また、A さんの自宅は H、市役所は D で表します。入力データに 2 つの地点とその間の距離が与えられているなら、2 地点の間をどちら向きにも進めます。たとえば、上の例ではケーキ屋さんからランドマークへも、その逆向きへも進むことができます。また、自宅から市役所までは必ずたどり着けるものとします。それ以外に与えられる入力データは、ケーキ屋さんの数 m、ランドマークの数 n、単位距離あたりの消費カロリー k、 1 番目のケーキ屋さんから m 番目のケーキ屋さんまでのそれぞれで買えるケーキのカロリーを表す m 個のデータ、距離のデータの総数 d です。

Input

複数のデータセットの並びが入力として与えられます。入力の終わりは四つの 0 の行で示されます。
各データセットは以下の形式で与えられます。

m n k d
c1 c2 ... cm
s1 t1 e1
s2 t2 e2
:
sd td ed

1 行目にケーキ屋さんの数 m (1 ≤ m ≤ 6)、 ランドマークの数 n (1 ≤ n ≤ 100) 、単位距離あたりの消費カロリー k (1 ≤ k ≤ 5)、距離のデータの総数 d (5 ≤ d ≤ 256) が与えられます。

2 行目に各ケーキ屋で買うケーキのカロリー ci (1 ≤ ci ≤ 100) が与えられます。

続く d 行に i 番目の 2 つの地点間の距離データ si, ti, ei (1 ≤ ei ≤ 20) が与えられます。

データセットの数は 100 を超えません。

Output

入力データセットごとに、全体の消費カロリーの最小値を１行に出力します。

Sample Input

1 1 2 5
35
H L1 5
C1 D 6
C1 H 12
L1 D 10
C1 L1 20
2 1 4 6
100 70
H L1 5
C1 L1 12
C1 D 11
C2 L1 7
C2 D 15
L1 D 8
0 0 0 0

Output for the Sample Input

1
-2

Solution in JAVA (judge verdict: Wrong Answer)

import java.util.Arrays;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Scanner;

public class Main {
	
	public static final int INF = Integer.MAX_VALUE / 2 - 1;
	public static final int M_MAX = 6;
	public static final int N_MAX = 100;
	public static final int MAX = M_MAX + N_MAX + 2;
	public static final int DP_MAX = M_MAX + 2;
	
	public static int node_num(int n, int m, String in){
		//System.out.println(in);
		
		if("H".equals(in)){
			return 0;
		}else if("D".equals(in)){
			return m + 1;
		}else{
			return Integer.parseInt(in.substring(1)) + (in.charAt(0) == 'L' ? m + 1 : 0);
		}
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int[][] adj = new int[MAX][MAX];
		int[][] cal_array  = new int[MAX][1 << M_MAX];
		
		while(true){
			final int m = sc.nextInt();
			final int n = sc.nextInt();
			final int k = sc.nextInt();
			final int d = sc.nextInt();
			
			if(n == 0 && m == 0 && k == 0 && d == 0){
				break;
			}
			
			final int max    = n + m + 2; 
			final int home   = 0;
			final int arrive = m + 1;
			
			int[] cals = new int[m + 2];
			for(int i = 0; i < m; i++){
				cals[i + 1] = sc.nextInt();
			}
			
			for(int i = 0; i < max; i++){
				for(int j = 0; j < max; j++){
					adj[i][j] = i == j ? 0 : INF;
				}
			}
			
			for(int i = 0; i < d; i++){
				String in1 = sc.next();
				String in2 = sc.next();
				
				//System.out.println(in1 + " " + in2);
				
				final int from = node_num(n, m, in1);
				final int to   = node_num(n, m, in2);
				
				//System.out.println(from + " " + to);
				
				final int dist = sc.nextInt();
				
				adj[from][to] = adj[to][from] = Math.min(adj[from][to], dist * k);
			}
			
			/*
			for(int i = 0; i < max; i++){
				for(int j = 0; j < max; j++){
					System.out.print(adj[i][j] + " ");
				}
				System.out.println();
			}
			*/
			
			for(int i = 0; i < max; i++){
				Arrays.fill(cal_array[i], INF);
			}
			
			final int m_bit = 1 << m;
			cal_array[0][0] = 0;
			while(true){
				boolean updated = false;
				
				for(int place = 0; place < max; place++){
					for(int bit = 0; bit < m_bit; bit++){
						if(cal_array[place][bit] >= INF){
							continue;
						}
						
						for(int next = 0; next < max; next++){
							if(place == next){
								continue;
							}else if(adj[place][next] >= INF){
								continue;
							}
							
							if(home < next && next < arrive){
								if((bit & (1 << (next - 1))) != 0){
									continue;
								}
								
								final int cost = 
										cal_array[place][bit] + 
										adj[place][next] - cals[next];
								
								if(cal_array[next][bit | (1 << (next - 1))] > cost){
									updated = true;
									cal_array[next][bit | (1 << (next - 1))] = cost;
								}
							}else{
								final int cost = 
										cal_array[place][bit] + 
										adj[place][next];
								
								if(cal_array[next][bit] > cost){
									updated = true;
									cal_array[next][bit] = cost;
								}
							}
							
						}
					}
				}
				
				//for(int i = 0; i < n; i++){
				//	System.out.println(Arrays.toString(cal_array[i]));
				//}
				
				if(!updated){
					break;
				}
			}
			
			System.out.println(cal_array[arrive][m_bit - 1]);
		}
	}
}