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

import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;

public class Main {

	static class Vertex implements Comparable <Vertex> {
		int id, ticket, d0;
		Vertex(int vertex, int ticket, int d0){
			this.id = vertex;
			this.ticket=ticket;
			this.d0 = d0;
		}
//		public boolean equals(Object v) {
//			return this.id == ((Vertex)v).id;
//		}
		public int compareTo(Vertex v) {
			return this.d0 - v.d0;
		}
	}
	
	static int inf = 100000000;
	public static void main(String args[]){
		try(Scanner sc=new Scanner(System.in)){
			while(sc.hasNext()) {
				int c=sc.nextInt();//割引券枚数
				int n=sc.nextInt();//町数
				int m=sc.nextInt();//路線数
				int s=sc.nextInt();//出発地
				int d=sc.nextInt();//目的地
				if(c==0) break;
				int[][] f=new int[n+1][n+1];//料金
				int[][] t=new int[n+1][c+1];//頂点と残っている割引券
				
				for(int i=0; i<m; i++) {
					int a=sc.nextInt();
					int b=sc.nextInt();
					f[a][b]=f[b][a]=sc.nextInt();
				}
				
				for(int i=1; i<=n; i++) {
					for(int j=c; j>=0; j--) {
						t[i][j]=inf;
					}
				}
				t[s][c]=0;
				PriorityQueue<Vertex> pq=new PriorityQueue<Vertex>();
				Vertex[][] vs=new Vertex[n+1][c+1];
//				for(int i=1; i<=n; i++) {
//					for(int j=c; j>=0; j--) {
//						vs[i][j]=new Vertex(i,j, t[i][j]);
//						pq.add(vs[i][j]);
//					}
//				}
				pq.add(new Vertex(s, c, 0));
				
				Map<Integer, Integer> prev=new HashMap<>();
				prev.put(s, 0);
				while(!pq.isEmpty()) {
					Vertex u=pq.remove();
					if(prev.containsKey(u.id)) {
						int keymin=Math.min(prev.get(u.id), u.d0);
						prev.remove(u.id);
						prev.put(u.id, keymin);
					}
					else {
						prev.put(u.id, u.d0);
					}
					for(int i=1; i<=n; i++) {
						if(f[u.id][i]>0) {
							int alt=u.d0+f[u.id][i];
							if(t[i][u.ticket]>alt) {
								t[i][u.ticket]=alt;
								pq.add(new Vertex(i, u.ticket, alt));
							}

							if(u.ticket>0 && t[i][u.ticket-1] > u.d0+f[u.id][i]/2) {
								t[i][u.ticket-1]=u.d0+f[u.id][i]/2;
								pq.add(new Vertex(i, u.ticket-1, u.d0+f[u.id][i]/2));
							}
						}
					}
				}

				int min=inf;
//				for(int i=c; i>=0; i--){
//					min=Math.min(t[d][i], min);
//				}
//				System.out.println(min);
				System.out.println(prev.get(d));
				
			}
		}
	}
}