Problem:
運送会社

白虎運送は会津若松市を代表する運送会社です。昨今の原油価格の高騰は運送会社にも多大なダメージを与え、運送会社各社では、できるだけ少ないガソリンで荷物を運ぶことが課題となっています。

白虎運送では、重い荷物を積んだトラックは、その走りだしに多くのエネルギーを必要とすることに着目しました。トラックが倉庫を出発してから一度も停止することなく目的地まで到達する経路の中で最短時間の経路を通ることで、ガソリンの節約ができると考えました。

あなたの仕事は、このような最短経路を計算できるカーナビを開発することです。作成するカーナビ用プログラムの仕様は以下のとおりです。

市内は、下図のように、東西方向の道路 M 本、南北方向の道路 N 本 からなる格子で表し、格子の各交点は交差点を表します。

交差点のいくつかには東西 - 南北の方向に信号機が設置されており、一定の周期で青、赤のシグナルが点灯しています。

市内の交差点間を結ぶ道路には工事中で通過できない個所がいくつかあります。

トラックが交差点から交差点へ移動するのに必要な時間は一定ですが、渋滞している道路ではさらに長い時間がかかります。

市内の道路情報、トラックが交差点間を移動するのに必要な時間、信号機がある交差点と各信号機の周期、工事中の道路、渋滞している道路と渋滞度、白虎運送の倉庫(始点)と目的地(終点)の位置を入力とし、始点から終点までの最短の時間を出力するプログラムを作成して下さい。

図のように、東西の方向の道路はa、b、c、... と英小文字で名前が付けられ 、南北の方向の道路は 1、2、3、... と整数で名前が付けられています。市内の交差点は、これらの英小文字と整数の組み合わせ H-V で指定されます。

例えば、市内の最北西の交差点は a-1 で指定されます。各信号は周期 k をもち、k 分ごとに切り替わります。東西が青ならば南北が赤で、南北が青ならば東西が赤です。黄色のシグナルは存在しません。トラックは二つの交差点を結ぶ道路を移動するのに D 分要しますが、その道路が渋滞している場合はさらに d 分の時間を要します。トラックは道路が工事中の場合は移動できません。

また、交差点に到達した時刻に、信号が赤の場合には進入できません。トラックは交差点でのみ、東、西、南、北に方向を変えることができますが、来た方向へは移動(Uターン)できません。道路は2方通行であり、トラックが行き来する時間、工事状況、渋滞度は2方向共通です。

初期状態として、トラックは東を向いていて、トラックが倉庫を出発する瞬間すべての信号機が南北の方向に青に切り替わるものとします。また、トラックは 100分以内で目的地に到達できるものとします。

Input

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

M N
D
ns
H1-V1 k1
H2-V2 k2
:
Hns-Vns kns
nc
H11-V11 H12-V12
H21-V21 H22-V22
:
Hnc1-Vnc1 Hnc2-Vnc2
nj
H11-V11 H12-V12 d1
H21-V21 H22-V22 d2
:
Hnj1-Vnj1 Hnj2-Vnj2 dnj
Hs-Vs Hd-Vd

１行目に道路の本数 M, N (2 ≤ M, N ≤ 20) が与えられます。２行目に、二つの交差点を結ぶ道路を移動するのに要する時間 D (1 ≤ D ≤ D, 整数) が与えられます。

３行目に信号機の数 ns が与えられます。続く ns 行に、i 個目の信号機の位置を表す英小文字と整数の組 Hi-Vi と周期 k (1 ≤ k ≤ 100) が与えられます。

続く行に、工事中の道路の数 nc が与えられます。続く nc 行に、i 個目の工事中の道路の２つの端点（交差点）を表す英小文字と整数の組 Hi1-Vi1 Hi2-Vi2 が与えられます。

続く行に、渋滞道路の数 nj が与えられます。続く nj 行に、i 個目の渋滞道路の２つの端点（交差点）を表す英小文字と整数の組 Hi1-Vi1 Hi2-Vi2 と時間 di (1 ≤ di ≤ 100) が与えられます。

最後の行に、始点の交差点 Hs-Vd と終点の交差点 Hd-Vd が与えられます。

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

Output

データセット毎に最短時間を１行に出力します。

Sample Input

4 5
1
3
b-2 3
c-3 2
c-4 1
3
a-2 b-2
b-3 c-3
d-3 d-4
2
b-3 b-4 1
c-1 d-1 1
d-1 b-4
4 5
1
3
b-2 3
c-3 2
c-4 1
3
a-2 b-2
b-3 c-3
d-3 d-4
2
b-3 b-4 1
c-1 d-1 1
d-2 b-4
4 5
1
3
b-2 3
c-3 2
c-4 1
3
a-2 b-2
b-3 c-3
d-3 d-4
2
b-3 b-4 1
c-1 d-1 1
d-3 b-4
0 0

Output for the Sample Input

7
4
8

Solution in C# (judge verdict: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace _0194
{
    public class Program

    {
        public enum Direction { S, W, N, E, Count }
        public static int[] di = new int[] { 1, 0, -1, 0 };
        public static int[] dj = new int[] { 0, -1, 0, 1 };

        public class State : IComparable<State>
        {
            public int I { get; set; }
            public int J { get; set; }
            public Direction AppDir { get; set; }
            public int Time { get; set; }
            public State(int i, int j, Direction appdir, int time)
            {
                I = i; J = j; AppDir = appdir; Time = time;
            }

            public int CompareTo(State other)
            {
                return  -1 * (Time - other.Time);
            }
        }

        public static bool[,,,] visited;//i,j,direction,time
        public static int d;
        public static int[,] signal; //i,j
        public static bool[,,] notPass; //i,j,direction
        public static int[,,] delay; //i,j,direction

        public static void Main(string[] args)
        {
            while (true)
            {
                int[] mn = RIntAr();
                if (mn.Sum() == 0) break;

                Init(mn);

                string[] startEnd = RStAr();
                string[] start = startEnd[0].Split('-');
                string[] end = startEnd[1].Split('-');

                PriorityQueue<State> q = new PriorityQueue<State>();
                q.Enqueue(new State(ChangeCharToInt(start[0][0]), int.Parse(start[1]) - 1, Direction.W, 0));

                int min = 100;

                while (q.Count > 0)
                {
                    State cur = q.Dequeue();
                    visited[cur.I, cur.J, (int)cur.AppDir, cur.Time] = true;

                    if (cur.I == ChangeCharToInt(end[0][0]) && cur.J == int.Parse(end[1]) - 1)
                    {
                        min = cur.Time;
                        break;
                    }

                    for (int i = 0 ; i < (int)Direction.Count ; i++)
                    {
                        if ((Direction)i == cur.AppDir) continue;

                        Direction nextD = (Direction)i;
                        int nextI = cur.I + di[(int)nextD];
                        int nextJ = cur.J + dj[(int)nextD];
                        int nextT = cur.Time + d + delay[cur.I, cur.J, (int)nextD];

                        if (IsInArea(nextI, nextJ) && nextT < min && !visited[nextI, nextJ, (int)GetOpponent(nextD), nextT])
                        {
                            if (!notPass[cur.I, cur.J, (int)nextD] && IsSignalOK(nextI, nextJ, GetOpponent(nextD), nextT))
                            {
                                q.Enqueue(new State(nextI, nextJ, GetOpponent(nextD), nextT));
                            }
                        }
                    }
                }

                Console.WriteLine(min);

            }
        }

        private static void Init(int[] mn)
        {

            d = RInt();
            visited = new bool[mn[0], mn[1], (int)Direction.Count, 101];

            signal = new int[mn[0], mn[1]];
            int ns = RInt();
            for (int k = 0 ; k < ns ; k++) //signal
            {
                string[] items = RStAr();
                string[] ij = items[0].Split('-');
                signal[ChangeCharToInt(ij[0][0]), int.Parse(ij[1]) - 1] = int.Parse(items[1]);
            }

            notPass = new bool[mn[0], mn[1], 4];
            int nc = RInt();
            for (int k = 0 ; k < nc ; k++)
            {
                string[] items = RStAr();
                string[] ij1 = items[0].Split('-');
                string[] ij2 = items[1].Split('-');
                notPass[ChangeCharToInt(ij1[0][0]), int.Parse(ij1[1]) - 1, (int)GetDirection(ij1, ij2)] = true;
                notPass[ChangeCharToInt(ij2[0][0]), int.Parse(ij2[1]) - 1, (int)GetDirection(ij2, ij1)] = true;
            }

            delay = new int[mn[0], mn[1], 4];
            int nj = RInt();
            for (int i = 0 ; i < nj ; i++)
            {
                string[] items = RStAr();
                string[] ij1 = items[0].Split('-');
                string[] ij2 = items[1].Split('-');
                delay[ChangeCharToInt(ij1[0][0]), int.Parse(ij1[1]) - 1, (int)GetDirection(ij1, ij2)] = int.Parse(items[2]);
                delay[ChangeCharToInt(ij2[0][0]), int.Parse(ij2[1]) - 1, (int)GetDirection(ij2, ij1)] = int.Parse(items[2]);
            }

        }

        private static int ChangeCharToInt(char c) { return c - 'a'; }

        private static Direction GetOpponent(Direction d) { return (Direction)(((int)d + 2) % (int)Direction.Count); }

        private static Direction GetDirection(string[] ij1, string[] ij2)
        {
            int si = ChangeCharToInt(ij1[0][0]);
            int sj = int.Parse(ij1[1]) - 1;
            int ti = ChangeCharToInt(ij2[0][0]);
            int tj = int.Parse(ij2[1]) - 1;

            if (si == ti)
            {
                if (sj < tj) return Direction.E;
                else return Direction.W;
            }
            else
            {
                if (si < ti) return Direction.S;
                else return Direction.N;
            }
        }

        private static bool IsSignalOK(int i, int j, Direction d, int time)
        {
            if (signal[i, j] == 0) return true;
            return (time / signal[i, j]) % 2 == (int)d % 2;
        }

        private static bool IsInArea(int i, int j)
        {
            return 0 <= i && i < visited.GetLength(0) && 0 <= j && j < visited.GetLength(1);
        }

        static string RSt() { return Console.ReadLine(); }
        static int RInt() { return int.Parse(Console.ReadLine().Trim()); }
        static long RLong() { return long.Parse(Console.ReadLine().Trim()); }
        static double RDouble() { return double.Parse(Console.ReadLine()); }
        static string[] RStAr(char sep = ' ') { return Console.ReadLine().Trim().Split(sep); }
        static int[] RIntAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => int.Parse(e)); }
        static long[] RLongAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => long.Parse(e)); }
        static double[] RDoubleAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => double.Parse(e)); }
        static string WAr<T>(IEnumerable<T> array, string sep = " ") { return string.Join(sep, array.Select(x => x.ToString()).ToArray()); }
    }

    public class PriorityQueue<T> where T : IComparable<T>

    {

        private List<T> Buffer { get; set; }

        public int Count { get { return Buffer.Count; } }

        public PriorityQueue() { Buffer = new List<T>(); }
        public PriorityQueue(int capacity) { Buffer = new List<T>(capacity); }


        /// <summary>
        /// ヒープ化されている配列リストに新しい要素を追加する。
        /// </summary>
        public void Enqueue(T item)
        {
            int n = Buffer.Count;
            Buffer.Add(item);

            while (n != 0)
            {
                int i = (n - 1) / 2;
                if (Buffer[n].CompareTo(Buffer[i]) > 0)
                {
                    T tmp = Buffer[n]; Buffer[n] = Buffer[i]; Buffer[i] = tmp;
                }
                n = i;
            }
        }

        /// <summary>
        /// ヒープから最大値を取り出し、削除する。
        /// </summary>
        public T Dequeue()
        {
            T ret = Buffer[0];
            int n = Buffer.Count - 1;
            Buffer[0] = Buffer[n];
            Buffer.RemoveAt(n);

            for (int i = 0, j ; (j = 2 * i + 1) < n ;)
            {
                if ((j != n - 1) && (Buffer[j].CompareTo(Buffer[j + 1]) < 0))
                    j++;
                if (Buffer[i].CompareTo(Buffer[j]) < 0)
                {
                    T tmp = Buffer[j]; Buffer[j] = Buffer[i]; Buffer[i] = tmp;
                }
                i = j;
            }
            return ret;
        }

        /// <summary>
        /// ヒープから最大値を参照する。
        /// </summary>
        public T Peek()
        {
            if (Count == 0) throw new InvalidOperationException();
            return this.Buffer[0];
        }
    }
}