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.*;
import static java.lang.Math.*;

public class Main {
	final Scanner sc=new Scanner(System.in);
	public static void main(String[] args) {
		new Main().init();
	}
	void init(){
		//new F();
		final long STACK_SIZE=8*1024*1024;
		new Thread(null, new D(), "", STACK_SIZE).start();
	}
	
	class D implements Runnable{
		final int INF=1<<29;
		int N;
		int[][] map;
		boolean[] leaf;
		@Override public void run(){
			while(sc.hasNext()){
				N=sc.nextInt();
				if(N==0)	break;
				solve();
			}
		}
		D(){}
//		D(){
//			while(sc.hasNext()){
//				N=sc.nextInt();
//				if(N==0)	break;
//				solve();
//			}
//		}
		void solve(){
			map=new int[N+1][N+1];
			leaf=new boolean[N+1];
			for(int i=0; i<=N; i++)for(int j=0; j<=N; j++)map[i][j]=INF;
			for(int i=0; i<N-1; i++){
				int a=sc.nextInt(),b=sc.nextInt(),t=sc.nextInt();
				map[a][b]=t;
			}
			int sum=DFS(1,0);
//			System.out.println(DFS(1,0));
			int[][] map2=new int[N+1][N+1];
			for(int i=0; i<=N; i++)for(int j=0; j<=N; j++)map2[i][j]=map[i][j];
			for(int i=0; i<=N; i++){
				for(int j=0; j<=N; j++){
					for(int k=0; k<=N; k++){
						map2[j][k]=min(map2[j][k], map2[j][i]+map2[i][k]);
					}
				}
			}
//			System.out.println(Arrays.toString(map2[1]));
			int max=0;
			for(int i=2; i<=N; i++){
				if(map2[1][i]>=INF || leaf[i])	continue;
				max=max(max,map2[1][i]);
			}
//			System.out.println("sum:"+sum+" max:"+max);
			System.out.println(2*sum-max);
		}
		int DFS(int now,int last){
			int ret=0,n=0;
			for(int i=1; i<=N; i++){
				if(i==now)	continue;
				if(!(map[now][i]<INF))	continue;
				int tmp=DFS(i,now);
				ret+=map[now][i]+tmp;
				++n;
//				System.out.println("now:"+now+" to:"+i+" tmp:"+tmp+" map"+map[now][i]);
			}
			ret-=n>0?0:map[last][now];
			if(n<=0)	leaf[now]=true;
			return ret;
		}
	}
	
	class E implements Runnable{
		@Override public void run(){
			while(sc.hasNext()){
				int N=sc.nextInt();
				if(N==0)	break;
				solve(N);
			}
		}
		E(){}
//		E(){
//			while(sc.hasNext()){
//				int N=sc.nextInt();
//				if(N==0)	break;
//				solve(N);
//			}
//		}
		void solve(int N){
			int[] d=new int[N],v=new int[N];
			for(int i=0; i<N; i++){
				d[i]=sc.nextInt();
				v[i]=sc.nextInt();
			}
			long vvv=v[0],ddd=d[0];
			for(int i=1; i<N; i++){
				long vv=v[i]*vvv;
				long d1=d[i]*vvv,d2=ddd*v[i];
				long d3=lcm(min(d1,d2),max(d1,d2));
				long gcd=gcd(d3,vv);
				vvv=vv/gcd;
				ddd=d3/gcd;
			}
			for(int i=0; i<N; i++){
				System.out.println(((long)v[i]*ddd/vvv)/(long)d[i]);
			}
		}
		long gcd(long x,long y){
			if(y==0)	return x;
			return gcd(y,x%y);
		}
		long lcm(long x,long y){
			return x/gcd(x,y)*y;
		}
	}
	class F implements Runnable{
		@Override public void run() {
			while(sc.hasNext()){
				int N=sc.nextInt();
				if(N==0)	break;
				System.out.println(solve(N)?"OK":"NG");
			}
		}
		F(){}
//		F(){
//			while(sc.hasNext()){
//				int N=sc.nextInt();
//				if(N==0)	break;
//				System.out.println(solve(N)?"OK":"NG");
//			}
//		}
		
		boolean solve(int N){
			String[] s=new String[N];
			for(int i=0; i<N; i++)	s[i]=sc.next();
			ArrayList<ArrayList<State1>> head=new ArrayList<ArrayList<State1>>(),
										tail=new ArrayList<ArrayList<State1>>();
			for(int i=0; i<(int)'z'-'a'; i++){
				head.add(new ArrayList<State1>());
				tail.add(new ArrayList<State1>());
			}
			for(int i=0; i<N; i++){
				head.get(s[i].charAt(0)-'a').add(new State1(i,s[i]));
				tail.get(s[i].charAt(s[i].length()-1)-'a').add(new State1(i,s[i]));
			}
			
			// TODO ok
			//System.out.println("head\n"+head);
			//System.out.println("tail\n"+tail);
			
			for(int i=0; i<(int)'z'-'a'; i++){
				boolean[] used=new boolean[N];
				for(int j=0; j<head.get(i).size(); j++){
					State1 h=head.get(i).remove(0);
					used[h.idx]=true;
					for(int k=0; k<tail.get(h.str.charAt(0)-'a').size(); k++){
						State1 t=tail.get(h.str.charAt(0)-'a').remove(0);
						// TODO ok
						//System.out.println("START2"+h+" "+t);
						if(!used[t.idx]){
							used[t.idx]=true;
							// TODO ok
							//System.out.println("START"+h+" "+t);
							if(DFS(N-2,head,tail,h.str.charAt(h.str.length()-1),t.str.charAt(0),used)){
								return true;
							}
							used[t.idx]=false;
						}
						tail.get(h.str.charAt(0)-'a').add(t);
					}
					head.get(i).add(h);
					used[h.idx]=false;
				}
			}
			return false;
		}
		boolean DFS(int remain,ArrayList<ArrayList<State1>> head,
						ArrayList<ArrayList<State1>> tail,char e,char s,boolean[] used){
			if(remain<=2){
				// TODO ok
				//System.out.println("END r:"+remain+" e:"+e+" s:"+s);
				if(head.get(e-'a').size()<=0)	return false;
				if(tail.get(s-'a').size()<=0)	return false;
				return true;
			}
			int N=head.get(e-'a').size(),M=tail.get(s-'a').size();
			LinkedList<State1> hstack=new LinkedList<State1>();
			for(int i=0; i<N; i++){
				hstack.push(head.get(e-'a').remove(0));
				if(used[hstack.peek().idx])	continue;
				char ee=hstack.peek().str.charAt(hstack.peek().str.length()-1);
				used[hstack.peek().idx]=true;
				LinkedList<State1> tstack=new LinkedList<State1>();
				for(int j=0; j<M; j++){
					tstack.push(tail.get(s-'a').remove(0));
					if(used[tstack.peek().idx])		continue;
					char ss=tstack.peek().str.charAt(0);
					used[tstack.peek().idx]=true;
					if(DFS(remain-2,head,tail,ee,ss,used))	return true;
					tail.get(s-'a').add(tstack.peek());
					used[tstack.pop().idx]=false;
				}
				for(State1 s1:tstack)	tail.get(s-'a').add(s1);
				head.get(e-'a').add(hstack.peek());
				used[hstack.pop().idx]=false;
			}
			for(State1 s1:hstack) head.get(e-'a').add(s1);
			return false;
		}
		class State1{
			int idx;
			String str;
			State1(int idx,String str){
				this.idx=idx;
				this.str=str;
			}
			@Override public String toString(){
				return "("+idx+":"+str+")";
			}
		}
	}
	

}