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 C++ (judge verdict: Accepted)

#include<queue>
#include<cstdio>
#include<cstdlib>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const int INF=1<<29;

struct edge{ int v,cost; };

int n_cake,n_land,home,goal;

int parse(const char *s){
	if(s[0]=='C') return atoi(s+1)-1;
	if(s[0]=='L') return atoi(s+1)-1+n_cake;
	if(s[0]=='H') return home;
	return goal;
}

int main(){
	for(int cal,m;scanf("%d%d%d%d",&n_cake,&n_land,&cal,&m),n_cake;){
		int cake[6];
		rep(u,n_cake) scanf("%d",cake+u);

		home=n_cake+n_land;
		goal=home+1;
		int n=goal+1;
		vector<edge> G[108];
		rep(i,m){
			char s[8],t[8];
			int d; scanf("%s%s%d",s,t,&d);
			int u=parse(s),v=parse(t);
			G[u].push_back((edge){v,d});
			G[v].push_back((edge){u,d});
		}

		int d[108][1<<6];
		rep(u,n) rep(S,1<<n_cake) d[u][S]=INF;
		d[home][0]=0;

		int ans=INF;
		priority_queue< pair< int,pair<int,int> > > Q;
		Q.push(make_pair(0,make_pair(home,0)));
		while(!Q.empty()){
			int d_now=-Q.top().first,u=Q.top().second.first,S=Q.top().second.second;
			Q.pop();

			if(d[u][S]<d_now) continue;

			if(u==goal) ans=min(ans,d_now);

			rep(i,G[u].size()){
				int v=G[u][i].v,S2,d2;
				if(v<n_cake){
					if(S&1<<v) continue;
					S2=S|1<<v;
					d2=d_now+cal*G[u][i].cost-cake[v];
				}
				else{
					S2=S;
					d2=d_now+cal*G[u][i].cost;
				}
				if(d2<d[v][S2]){
					d[v][S2]=d2;
					Q.push(make_pair(-d2,make_pair(v,S2)));
				}
			}
		}

		printf("%d\n",ans);
	}

	return 0;
}