Problem:
サージェント・ライアン

「ライアン軍曹を救え」という指令のもと、アイヅ軍の救出部隊はドイツリーの水上都市で敵軍と激しい戦闘を繰り広げていました。彼らは無事に軍曹と合流しましたが、敵の戦車が多く、救出ヘリを呼べずにいました。そこで、彼らは敵の戦車を混乱させるため、都市にある橋を全て爆破するという作戦を実行することにしました。

作戦はすぐに司令部に伝えられ、救出ヘリの準備が進められました。救出ヘリを飛ばすためには、いつ橋が全て爆破されるかを予測しなければなりません。軍のプログラマであるあなたの任務は、救出部隊が全ての橋の爆破に必要な時間を計算することです。

水上都市は N 個の島で構成されており、島と島との間には橋がかかっています。すべての島はツリー状に繋がっています(下図参照) 。ある島からある島への経路は、一通りだけ存在します。各橋を渡るには、橋ごとに決められた時間がかかり、どちらの方向にもその時間で橋を渡ることが可能です。

救出部隊はボートなど水上を移動する手段を持っていないので島と島の間を移動するには橋を通る他ありません。救出部隊は、その時いる島に隣接している橋のうち、必要なものを一瞬で爆破することができます。救出部隊が全ての橋を爆破するのに必要な最小の時間はいくらでしょうか。ただし、島の中での移動時間は考えません。

島の数、それぞれの橋情報を入力とし、橋を全て爆破するのに必要な最小の時間を出力するプログラムを作成してください。島はそれぞれ 1 から N の番号で表されます。橋は N-1 本あります。橋情報は、その橋が隣接している二つの島の番号(a, b)と、その橋を渡るのに必要な時間 t で構成されます。救出部隊は島番号 1 の島からスタートするものとします。

Input

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

N
a1 b1 t1
a2 b2 t2
:
aN-1 bN-1 tN-1

入力はすべて整数で与えられる。1 行目に島の数 N (2 ≤ N ≤ 20) が与えられる。

続く N-1 行に i 番目の橋の情報が与えられる。 ai, bi, ti (1 ≤ ti ≤ 500) は、i 番目の橋を通って島 ai と島 bi の間を時間 ti で移動できることを表す。

データセットの数は 100 を超えない。

Output

データセットごとに、橋を全て爆破するのに必要な最小の時間を1行に出力する。

Sample Input

7
1 2 5
2 3 2
3 4 3
2 5 3
5 6 3
5 7 8
0

Output for the Sample Input

12

Solution in JAVA (judge verdict: Accepted)


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		new Main().run();
	}

	@SuppressWarnings("unchecked")
	private void run() {
		Scanner scanner = new Scanner(System.in);
		while (true) {
			n = scanner.nextInt();
			if (n == 0)
				break;
			lists = new ArrayList[n];
			for (int i = 0; i < n; i++)
				lists[i] = new ArrayList<Edge>();
			for (int i = 0; i < n - 1; i++) {
				int from = scanner.nextInt() - 1;
				int to = scanner.nextInt() - 1;
				int cost = scanner.nextInt();
				lists[from].add(new Edge(to, cost));
				lists[to].add(new Edge(from, cost));
			}
			for (int i = 0; i < n; i++) {
				if (lists[i].size() == 1 && i != 0) {
					lists[i].get(0).cost = INF;
				}
			}
			int sum = 0;
			for (int i = 0; i < n; i++) {
				if (lists[i].size() == 1 && i != 0)
					continue;
				for (Edge edge : lists[i]) {
					if (lists[edge.to].get(0).cost == INF)
						continue;
					sum += edge.cost;
				}
			}
			PriorityQueue<Edge> pq = new PriorityQueue<Edge>();
			pq.offer(new Edge(0, 0));
			int[] costs = new int[n];
			Arrays.fill(costs, 1 << 24);
			costs[0] = 0;
			while (!pq.isEmpty()) {
				Edge edge = pq.poll();
				for (Edge e : lists[edge.to]) {
					if(lists[e.to].get(0).cost==INF)
						continue;
					if (costs[e.to] > e.cost + edge.cost) {
						costs[e.to] = e.cost + edge.cost;
						pq.offer(new Edge(e.to, costs[e.to]));
					}
				}
			}
			int max = 0;
			for (int ans : costs) {
				if (ans == INF)
					continue;
				max = Math.max(max, ans);
			}
			System.out.println(sum - max);
		}
	}

	int n;
	List<Edge>[] lists;
	int INF = 1 << 24;

	class Edge implements Comparable<Edge> {
		int to, cost;

		Edge() {
		}

		public Edge(int to, int cost) {
			super();
			this.to = to;
			this.cost = cost;
		}

		@Override
		public String toString() {
			return "Edge [to=" + to + ", cost=" + cost + "]";
		}

		@Override
		public int compareTo(Edge o) {
			return this.cost - o.cost;
		}

	}
}