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: Accepted)

import java.util.*;

public class Main{
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int INF = Integer.MAX_VALUE;

		while(true){
			int m = sc.nextInt();
			int n = sc.nextInt();
			int k = sc.nextInt();
			int d = sc.nextInt();
			if(m == 0) break;

			int[] cake = new int[m];
			for(int i=0;i<m;i++)
				cake[i] = sc.nextInt();

			//[0]:X^[g
			//[1]~[m]:P[L®
			//[m+1]~[m+n]:h}[N
			//[m+n+1]:sð
			int[][] map = new int[m+n+2][m+n+2];
			for(int[] tmp : map) Arrays.fill(tmp,INF);

			for(int i=0;i<d;i++){
				String a = sc.next();
				String b = sc.next();
				int cost = sc.nextInt();
				int from=-1,to=-1;

				if(a.equals("H")) from = 0;
				else if(a.equals("D")) from = m+n+1;
				else if(a.charAt(0) == 'C') from = Integer.parseInt(a.substring(1));
				else from = m + Integer.parseInt(a.substring(1));

				if(b.equals("H")) to = 0;
				else if(b.equals("D")) to = m+n+1;
				else if(b.charAt(0) == 'C') to = Integer.parseInt(b.substring(1));
				else to = m + Integer.parseInt(b.substring(1));

				map[from][to] = map[to][from] = k * cost;
			}

			PriorityQueue<State> open = new PriorityQueue<State>();
			int[][] closed = new int[m+n+4][1000];
			for(int[] tmp : closed) Arrays.fill(tmp,INF);
			int ans = INF;
			open.add(new State(0,0,0));

			while(!open.isEmpty()){
				State st = open.poll();
				if(closed[st.id][st.used] <= st.cost) continue;
				closed[st.id][st.used] = st.cost;

				if(st.id == m+n+1){
					ans = Math.min(ans,st.cost);
				}

				for(int i=0;i<m+n+2;i++){
					if(map[st.id][i] != INF && ( i<1 || m<i || (st.used & (1<<i)) == 0 ) ){
						int ncost = st.cost + map[st.id][i];
						int nused = st.used;
						if(1 <= i && i <= m){
							ncost -= cake[i-1];
							nused |= (1<<i);
						}
						if(closed[i][nused] > ncost)
							open.add(new State(ncost,i,nused));
					}
				}
			}

			System.out.println(ans);
		}
	}
}

class State implements Comparable<State>{
	int cost,id,used;

	State(int cost,int id,int used){
		this.cost = cost;
		this.id = id;
		this.used = used;
	}

	public int compareTo(State st){
		return this.cost - st.cost;
	}
}