Problem:
最古の遺跡

問題

昔, そこには集落があり, 多くの人が暮らしていた. 人々は形も大きさも様々な建物を建てた. だが, それらの建造物は既に失われ, 文献と, 遺跡から見つかった柱だけが建造物の位置を知る手がかりだった.

文献には神殿の記述がある. 神殿は上から見ると正確に正方形になっており, その四隅には柱があった. 神殿がどの向きを向いていたかはわからない. また, 辺上や内部に柱があったかどうかもわからない. 考古学者たちは, 遺跡から見つかった柱の中で, 正方形になっているもののうち, 面積が最大のものが神殿に違いないと考えた.

柱の位置の座標が与えられるので, 4 本の柱でできる正方形のうち面積が最大のものを探し, その面積を出力するプログラムを書け. なお, 正方形の辺は座標軸に平行とは限らないことに注意せよ.

例

下の図の例では, 10 本の柱があり, 座標 (4, 2), (5, 2), (5, 3), (4, 3) にある 4 本と座標 (1, 1), (4, 0), (5, 3), (2, 4) にある 4 本が正方形をなしている. 面積が最大の正方形は後者で, その面積は 10 である.

入力

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

1 行目には, 遺跡から見つかった柱の本数 n が書かれている.

2 行目から n + 1 行目までの n 行の各々には, 柱の x 座標と y 座標が空白区切りで書かれている.

1 本の柱が 2 度以上現れることはない.

n は 1 ≤ n ≤ 3000 を満たす整数であり, 柱の x 座標と y 座標は 0 以上 5000 以下の整数である.

採点用データのうち, 配点の 30% 分は 1 ≤ n ≤ 100 を満たし, 配点の 60% 分は1 ≤ n ≤ 500 を満たす.

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

出力

データセットごとに 1 個の整数を出力する. 4 本の柱からなる正方形が存在する場合は, そのような正方形のうち面積が最大のものの面積を出力し, そのような正方形が存在しない場合は 0 を出力せよ.

入出力例

入力例

10
9 4
4 3
1 1
4 2
2 4
5 8
4 0
5 3
0 5
5 2
10
9 4
4 3
1 1
4 2
2 4
5 8
4 0
5 3
0 5
5 2
0

出力例

10
10

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

Solution in JAVA (judge verdict: Time Limit Exceeded)

import java.awt.Point;
import java.util.Scanner;

public class Main {
	public static void main(String args[]) {
		Scanner sc = new Scanner(System.in);
		int n;
		Point p[];
		int s, max;

		n = sc.nextInt();
		while (n != 0) {
			p = new Point[n];
			max = 0;
			s = 0;

			for (int i = 0; i < n; i++) {
				int x = sc.nextInt();
				int y = sc.nextInt();
				p[i] = new Point(x, y);
			}

			quickSort(p, 0, n - 1);

			for (int i = 0; i < n - 1; i++) {
				for (int j = n - 1; i < j; j--) {
					int a = (p[j].x - p[i].x) * (p[j].x - p[i].x) + (p[j].y - p[i].y) * (p[j].y - p[i].y);
					if (max < a) {
						s = f(p, n, i, j);
					}
					if (max < s) {
						max = s;
					}
				}
			}

			System.out.println(max);
			n = sc.nextInt();
		}
	}

	public static int f(Point p[], int n, int a, int b) {
		int x = p[b].x - p[a].x;
		int y = p[b].y - p[a].y;
		boolean flag = false;
		Point c1 = new Point(p[b].x - y, p[b].y + x);
		Point d1 = new Point(p[a].x - y, p[a].y + x);
		Point c2 = new Point(p[b].x + y, p[b].y - x);
		Point d2 = new Point(p[a].x + y, p[a].y - x);

		for (int i = 0; i < n && !flag && p[i].x <= c1.x; i++) {
			if (p[i].equals(c1)) {
				flag = true;
			}
		}
		for (int i = 0; i < n && flag && p[i].x <= d1.x; i++) {
			if (p[i].equals(new Point(d1))) {
				return x * x + y * y;
			}
		}

		flag = false;
		for (int i = 0; i < n && !flag; i++) {
			if (p[i].equals(c2)) {
				flag = true;
			}
		}
		for (int i = 0; i < n && flag; i++) {
			if (p[i].equals(new Point(d2))) {
				return x * x + y * y;
			}
		}

		return 0;
	}

	public static void quickSort(Point p[], int low, int high) {
		if (high <= low) {
			return ;
		}

		int i = low;
		int j = high;
		int x = p[(low + high) / 2].x;

		while (i <= j) {
			while (p[i].x < x) {
				i++;
			}
			while (x < p[j].x) {
				j--;
			}
			if (i <= j) {
				Point swap = p[i];
				p[i] = p[j];
				p[j] = swap;
				i++;
				j--;
			}
		}
		quickSort(p, low, j);
		quickSort(p, i, high);
	}
}