Problem:
最軽量のモビール

問題

モビールは動く芸術品として広く親しまれている.IOI 日本委員会では,JOI を広報するためにモビールを作成することになった.JOI 広報用モビールは,棒,紐(ひも),錘(おもり)の 3 種類の要素を用いて,次のように構成される.

棒の一方の端は青に,もう一方の端は赤に塗られている.

棒は両端以外の 1 箇所を支点として紐でつるされる.

支点から赤の端までの長さも支点から青の端までの長さも正整数である.

棒の両端には,紐で錘か他の棒をつるす.

錘は紐を用いてどれかの棒の一端につるされる.

錘には何もつるさない.

錘の重さは正整数である.

紐のうち 1 本だけは,片方の端をある棒をつるすためにその棒の支点に結ばれ,
もう一方の端は他のどの構成要素とも結ばれていない.他の紐は全て次のいず
れかを満たす.

ある棒の端とある棒の支点を結ぶ.

ある棒の端とある錘を結ぶ.

ただし,どの棒においても,バランスが取れている必要がある.棒と紐の重さは無視できるほど軽いので,棒と紐の重さは全て 0 であるとみなして解答せよ.つまり,それぞれの棒について,

(その棒の赤の端より下につるされている錘の重さの総計)
× (その棒の支点から赤の端までの長さ)
= (その棒の青の端より下につるされている錘の重さの総計)
× (その棒の支点から青の端までの長さ)

であるとき,その棒はバランスが取れているとせよ.

どのような長さの棒をどのように結びモビールを構成するかは既に決まっているのだが,錘の重さがまだ決まっていない.モビールは軽い方がつりやすいため, なるべく軽いモビールを作りたい.前述したようにどの棒もバランスを取りながら, モビールの総重量を最小にするような錘の付け方を求め, そのときのモビールの総重量を出力するプログラムを作れ. プログラムには以下のモビールの構成に関する情報が与えられる.

棒の本数 n

各棒ごとの情報(棒の番号は 1 から n)

支点から赤の端までの長さと支点から青の端までの長さの比

赤の端につるす棒の番号 (錘をつるす場合は 0)

青の端につるす棒の番号 (錘をつるす場合は 0)

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．入力はゼロ１つを含む行で終了する．

1 行目にはモビールに使われている棒の本数 n が書かれている.続く n 行 (1 ≤ n ≤ 100) には,各々の棒のデータが書かれている.i + 1 行目 (1 ≤ i ≤ n) には,4 つの整数 p, q, r, b が空白を区切りとして書かれており,棒 i において,支点から赤の端までの長さと支点から青の端までの比が p : q であり,赤の端につるされる棒の番号が r であり,青の端につるされる棒の番号が b であることを表している.ただし,棒番号 0 は錘がつるされることを表している.また,どの入力においても,モビールの重量の最小値を w とし,入力中で比を表すのに用いられる正整数の最大値を L とすると,wL < 231 を満たす.

データセットの数は 15 を超えない．

出力

データセットごとにモビールの重量を１行に出力する．

入出力例

入力例

1
6 9 0 0
4
3 2 0 4
1 3 0 0
4 4 2 1
2 2 0 0
0

出力例

5
40

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in JAVA (judge verdict: Wrong Answer)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

/**
 * Lightest Mobile
 */
public class Main {

	static Main main = new Main();

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String line = "";

		// int d = 0;
		Mobile mobile = null;
		while (!(line = br.readLine()).equals("0")) {
			int n = Integer.parseInt(line);
			// d++;

			mobile = main.new Mobile();
			for (int i = 1; i <= n; i++) {
				line = br.readLine();
				mobile.add(i, line);
			}
			// if (d == 11)
			// System.err.println(mobile.mobile.size());
			System.out.println(mobile.calc());
		}
	}

	class Mobile {
		ArrayList<Bar> mobile = new ArrayList<Bar>();

		// 棒をモービルに追加
		void add(int id, String info) {
			HangableImpr parent, left, right;
			int lid, rid;
			int lengthL, lengthR;

			StringTokenizer st = new StringTokenizer(info);
			lengthL = Integer.parseInt(st.nextToken());
			lengthR = Integer.parseInt(st.nextToken());

			// 親の棒
			if ((parent = find(id)) == null) {
				parent = new Bar(id, null);
			}
			((Bar) parent).lengthL = lengthL;
			((Bar) parent).lengthR = lengthR;

			lid = Integer.parseInt(st.nextToken());
			rid = Integer.parseInt(st.nextToken());

			// 左の棒
			if (lid == 0) {
				left = new Spindle();
				left.parent = parent;
			} else {
				if ((left = find(lid)) == null) {
					left = new Bar(lid, (Bar) parent);
				} else {
					((Bar) left).parent = (Bar) parent;
					mobile.remove(left);
				}
			}

			// 右の棒
			if (rid == 0) {
				right = new Spindle();
				right.parent = parent;
			} else {
				if ((right = find(rid)) == null) {
					right = new Bar(rid, (Bar) parent);
				} else {
					((Bar) right).parent = (Bar) parent;
					mobile.remove(right);
				}
			}
			((Bar) parent).left = left;
			((Bar) parent).right = right;
			if (((Bar) parent).parent == null) {
				mobile.add((Bar) parent);
			}
		}

		// 指定した id の棒を検索
		Bar find(int id) {
			Bar result = null;
			for (Bar b : mobile) {
				result = b.find(id);
				if (result != null)
					break;
			}
			return result;
		}

		long calc() {
			long result = 0;
			for (Bar b : mobile) {
				b.calc();
				result = b.weight;
			}
			return result;
		}
	}

	//
	interface Hangable {
		Hangable find(int id);
	}

	abstract class HangableImpr implements Hangable {
		HangableImpr parent;
		long weight = 0;
	}

	class Spindle extends HangableImpr {
		// int weight = 0;
		// Bar parent;

		Spindle() {
			this.weight = 0;
		}

		Spindle(int weight) {
			this.weight = weight;
		}

		public Spindle find(int id) {
			return null;
		}
	}

	class Bar extends HangableImpr {
		int id;
		int lengthL, lengthR;
		// Bar parent;
		HangableImpr parent, left, right;

		Bar(int id, Bar parent) {
			this.id = id;
			this.parent = parent;
		}

		public Bar find(int id) {
			Bar result = null;
			if (this.id == id)
				result = this;
			if (result == null && left != null)
				result = (Bar) left.find(id);
			if (result == null && right != null)
				result = (Bar) right.find(id);
			return result;
		}

		void calc() {
			if (left instanceof Bar) {
				((Bar) left).calc();
			}
			if (right instanceof Bar) {
				((Bar) right).calc();
			}

			long gcd = gcd(lengthL, lengthR);
			long tempL, tempR;
			long weightL, weightR;

			tempL = lengthL / gcd;
			tempR = lengthR / gcd;
			weightL = left.weight;
			weightR = right.weight;

			if (weightL == 0 && weightR == 0) {
				left.weight = tempR;
				right.weight = tempL;
			} else if (weightL != 0 && weightR == 0) {
				long lcm = lcm(tempR, lcm(tempL, weightL));
				left.weight = lcm / tempL;
				right.weight = lcm / tempR;
			} else if (weightL == 0 && weightR != 0) {
				long lcm = lcm(tempL, lcm(tempR, weightR));
				left.weight = lcm / tempL;
				right.weight = lcm / tempR;
			} else {
				long lcm = lcm(lcm(tempL, weightL), lcm(tempR, weightR));
				left.weight = lcm / tempL;
				right.weight = lcm / tempR;
			}
			weight = left.weight + right.weight;
		}
	}

	// 最小公倍数
	static long lcm(long l, long r) {
		long gt = l > r ? l : r;
		long lt = l < r ? l : r;
		return lt * (gt / gcd(l, r));
	}

	static long lcm(long l, long r, long gcd) {
		long gt = l > r ? l : r;
		long lt = l < r ? l : r;
		return lt * (gt / gcd);
	}

	// 最大公約数
	static long gcd(long l, long r) {
		long mod;
		long gt = l > r ? l : r;
		long lt = l < r ? l : r;

		do {
			mod = gt % lt;
			gt = lt;
			lt = mod;
		} while (mod != 0);

		return gt;
	}
}