Codeforces #34 (div2) E "Collisions"

問題:http://codeforces.com/contest/34/problem/E

ラクティス.
ボールの位置,速度,重量が与えられ,ある時間になったときの各ボールの座標を求める問題.
衝突を考慮し,衝突する場合は規定の式を用いる.
本番中に方針は分かってたものの実装が間に合わず未提出.


最初に座標の位置でソートする.これ以降ボールの順番はいくら衝突しようが変わらないはず.
次に位置と速度から隣り合うボール同士の中で一番最初にぶつかる時間を計算し,各ボールの位置と,衝突する場合はその速度を更新する.これを求めたい時間まで繰り返す.
最後に入力されたボールの順番にソートしなおして出力.

浮動小数点の誤差を考慮することに慣れてなかったため,いろいろと引っかかってた.テストケースが公開されてたのは非常に助かった.
http://codeforces.com/blog/entry/746

import java.util.*;

public class E_Collisions {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextInt(), T = s.nextInt();
		List<double[]> m = new ArrayList<double[]>();
		for (int i = 0; i < n; ++i) {
			double[] d = new double[4];
			d[0] = i;
			for (int j = 1; j < 4; ++j) {
				d[j] = s.nextInt();
			}
			m.add(d);
		}
		Collections.sort(m, new Comparator<double[]>() {
			@Override
			public int compare(double[] o1, double[] o2) {
				return Double.compare(o1[1], o2[1]);
			}
		});
		for (double t=0; Double.compare(t,T)<0;) {
			List<Double>q=new ArrayList<Double>();
			q.add(T-t);
			for (int i = 0; i < n - 1; ++i) {
				// 隣接するボール同士が衝突する時間を求める
				double[]x=m.get(i),y=m.get(i+1);
				if(x[2]-y[2]>0&&Math.abs(x[1]-y[1])>1e-5){
					q.add((y[1]-x[1])/(x[2]-y[2]));
				}
			}
			Collections.sort(q);
			double t1=q.get(0);
			// t1秒後におけるすべてのボールの位置を更新.
			for(double[] d : m){
				d[1] += d[2] * t1;
			}
			// 接触するボールは規定の式を用いて速度も更新.
			for(int  i = 0; i < m.size()-1; ++i){
				double[] x=m.get(i),y=m.get(i+1);
				double xv=x[2], yv=y[2];
				if(Math.abs(x[1]-y[1])<1e-5){
					xv = v(x[2],x[3],y[2],y[3]);
					yv = v(y[2],y[3],x[2],x[3]);
				}
				x[2] = xv;
				y[2] = yv;
				
			}
			t += t1;
		}
		Collections.sort(m, new Comparator<double[]>() {
			@Override
			public int compare(double[] o1, double[] o2) {
				return Double.compare(o1[0], o2[0]);
			}
		});
		for(double[]d:m){
			System.out.println(d[1]);
		}
	}
	
	static private double v(double xv, double xm, double yv, double ym){
		return ((xm-ym)*xv+2*ym*yv)/(xm+ym);
	}
}