Problem:
高速バス

A 君は高校の休みを利用して、高速バス(以下、「バス」 )で一人旅をする計画を立てています。まず、A 君は一番行ってみたい町を選んでそこを目的地にしました。次に出発地から目的地までバスを乗り継いでいくルートを決めなければなりません。乗り継ぎをするときは、バスを降りてから別のバスに乗り換えるので、それぞれのバスの乗車券が必要になります。

A 君は親戚のおじさんからバスの割引券を何枚かもらいました。 この券を 1 枚使うと乗車券 1 枚を半額で購入できます。例えば、図 1 の出発地5から目的地1へ行く場合には、5→4→6→2→1と5→3→1の二つの経路が考えられます。割引券が 2 枚あるとすると、交通費を最も安くするには5→4→6→2→1の経路をたどった場合、4→6と6→2の路線に割引を利用し、合計料金は 4600円となります。一方、5→3→1の経路をたどった場合、5→3と3→1の路線に割引を利用し、合計料金は 3750 円となります。

A 君は観光にお金を回したいので、交通費はできるだけ少なくしようと考えています。そこで A 君は、出発地から目的地までの最も安い交通費を求めるプログラムを作成することにしました。

図1

割引券の枚数、バスがつなぐ町の数、バスの路線数、各バスの路線情報を入力とし、出発地から目的地までの最も安い交通費を出力するプログラムを作成してください。各バスは双方向に同一料金で運行しています。また、町の数を n とすると、町にはそれぞれ異なる 1 から n までの番号が振られています。出発地から目的地までの経路は必ず存在するものとします。

Input

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

c n m s d
a1 b1 f1
a2 b2 f2
:
am bm fm

1 行目に割引券の枚数 c (1 ≤ c ≤ 10)、バスがつなぐ町の数 n (2 ≤ n ≤ 100)、バスの路線数 m (1 ≤ m ≤ 500)、出発地の町番号 s と目的地の町番号 d (s ≠ d) が与えられます。

続く m 行に第 i のバスの路線情報 ai, bi, fi (1 ≤ ai, bi ≤ n, 1000 ≤ fi ≤ 10000) が与えられます。ai, bi はバスの路線の始点と終点の町番号、fi はこの路線の料金を表す100 刻みの整数です。

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

Output

入力データセットごとに、最も安い交通費を１行に出力します。

Sample Input

1 3 3 1 3
1 3 2000
1 2 1000
2 3 1000
2 3 3 1 3
1 3 2300
1 2 1000
2 3 1200
2 6 6 5 1
1 2 1500
1 3 4500
2 6 2000
5 4 1000
6 4 2200
3 5 3000
0 0 0 0 0

Output for the Sample Input

1000
1100
3750

Solution in C# (judge verdict: Accepted)

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

namespace _0212
{
    public class Program

    {
        public static void Main(string[] args)
        {
            while (true)
            {
                int[] vs = RIntAr();
                if (vs.Sum() == 0) break;
                Init(vs);
                Dijkstra(new IDAndRem(vs[3], vs[0]));
                Console.WriteLine(Adj.Where(x => x.Key.ID == vs[4]).Min(x => x.Value.Distance));
            }
        }

        private static void Init(int[] vs)
        {
            Adj = new Dictionary<IDAndRem, Node>();
            int c = vs[0], n = vs[1], m = vs[2];

            for (int i = 1; i <= n; i++)
            {
                for (int j = 0; j <= c; j++)
                {
                    Adj.Add(new IDAndRem(i, j), new Node());
                }
            }

            for (int i = 0; i < m; i++)
            {
                int[] items = RIntAr();
                for (int j = c; j >= 0; j--)
                {
                    Adj[new IDAndRem(items[0], j)].Vertex.Add(new KeyValuePair<IDAndRem, int>(new IDAndRem(items[1], j), items[2]));
                    Adj[new IDAndRem(items[1], j)].Vertex.Add(new KeyValuePair<IDAndRem, int>(new IDAndRem(items[0], j), items[2]));

                    if (j > 0)
                    {
                        Adj[new IDAndRem(items[0], j)].Vertex.Add(new KeyValuePair<IDAndRem, int>(new IDAndRem(items[1], j - 1), items[2] / 2));
                        Adj[new IDAndRem(items[1], j)].Vertex.Add(new KeyValuePair<IDAndRem, int>(new IDAndRem(items[0], j - 1), items[2] / 2));
                    }
                }
            }
        }

        public class IDAndRem : IEquatable<IDAndRem>
        {
            public int ID { get; set; }
            public int RemTicket { get; set; }
            public IDAndRem(int iD, int remTicket)
            {
                ID = iD;
                RemTicket = remTicket;
            }

            public bool Equals(IDAndRem other)
            {
                if (other == null) return false;
                else return ID == other.ID && RemTicket == other.RemTicket;
            }

            public override int GetHashCode()
            {
                return ID.GetHashCode() ^ RemTicket.GetHashCode();
            }
        }

        public class Node
        {
            public List<KeyValuePair<IDAndRem, int>> Vertex { get; internal set; }
            public int Distance { get; internal set; }
            public Node()
            {
                Vertex = new List<KeyValuePair<IDAndRem, int>>();
                Distance = int.MaxValue;
            }
        }

        public static Dictionary<IDAndRem, Node> Adj { get; set; }

        /// <summary>
        /// 始点からの距離をセットする（ダイクストラ法）
        /// </summary>
        /// <param name="s">始点</param>
        class Candidate : IComparable<Candidate>
        {
            public IDAndRem V { get; set; }
            public int Distance { get; set; }

            public Candidate(IDAndRem v, int d) { Distance = d; V = v; }
            public int CompareTo(Candidate other) { return -1 * Distance.CompareTo(other.Distance); }
        }
        public static void Dijkstra(IDAndRem s)
        {
            foreach (var item in Adj) item.Value.Distance = int.MaxValue;

            Adj[s].Distance = 0;
            PriorityQueue<Candidate> pq = new PriorityQueue<Candidate>();
            pq.Enqueue(new Candidate(s, Adj[s].Distance));

            while (pq.Count > 0)
            {

                Candidate c = pq.Dequeue();
                IDAndRem v = c.V;
                int d = c.Distance;

                if (Adj[v].Distance < c.Distance) continue;

                foreach (KeyValuePair<IDAndRem, int> nextV in Adj[v].Vertex)
                {
                    if (Adj[nextV.Key].Distance > Adj[v].Distance + nextV.Value)
                    {
                        Adj[nextV.Key].Distance = Adj[v].Distance + nextV.Value;
                        pq.Enqueue(new Candidate(nextV.Key, Adj[nextV.Key].Distance));
                    }
                }
            }
        }

        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];
        }
    }

}