Problem:
シールの重なり

1 辺の長さが 10 の正方形の折り紙に半径 1 の円形のシールを n 枚貼ります。シールは重ねて貼ることができます。シールを貼る位置の座標を読み込んで、折り紙上でもっとも多くシールが重なっている場所(シールが１枚だけでも"重なっている"とする)でのシールの枚数を出力するプログラムを作成してください。

折り紙の左下を原点とした x, y 座標を与えます。この x, y を円の中心としてシールを貼ることとします。円の中心が折り紙の外に出ることはありません。また、同一座標に複数のシールが貼られることはありません。

Input

複数のデータセットが与えられます。各データセットは以下のような形式で与えられます。

n
x1,y1
x2,y2
:
xn,yn

１行目にシールの枚数 n (0 ≤ 100) が与えられます。続く n 行に、各シールの中心座標が与えられます。
xi, yi は i 枚目のシールの中心の x 座標と y 座標を表します。各値は小数点以下最大 6 桁までの数字を含む実数で与えられます。

n が 0 のとき、入力の最後とします。データセットの数は 50 を超えません。

Output

各データセットに対し、折り紙上で最も多くシールが重なっている場所でのシールの枚数（整数）を出力して下さい。

Sample Input

15
3.14979,8.51743
2.39506,3.84915
2.68432,5.39095
5.61904,9.16332
7.85653,4.75593
2.84021,5.41511
1.79500,8.59211
7.55389,8.17604
4.70665,4.66125
1.63470,4.42538
7.34959,4.61981
5.09003,8.11122
5.24373,1.30066
0.13517,1.83659
7.57313,1.58150
0

Output for the Sample Input

4

Hint

入力例のようにシールを貼った図です。円はシール、数字は入力例の行数を表しています。
点(2.3,4.6)では、入力例の 2 行目、3 行目、6 行目、10 行目の 4 枚のシールが重なっています。

6 と 9 のおのおのの中心の距離は 2.01293 なので、シールは重なっていません。1 と 12 のおのおのの中心の距離は 1.98231 なので、シールは重なっています。

２つの円が接しているとき（おのおのの中心の距離が 2 のとき）は、重なっているものとします。

Solution in JAVA (judge verdict: Accepted)

import java.util.LinkedList;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		while (true) {
			final int n = sc.nextInt();
			
			if(n == 0){
				break;
			}

			Point2D[] input = new Point2D[n];
			
			for(int i = 0; i < n; i++){
				String[] str = sc.next().split(",");
				input[i] = new Point2D(Double.parseDouble(str[0]), Double.parseDouble(str[1]));
			}
			
			LinkedList<Point2D> list = new LinkedList<Point2D>();
			
			for(int i = 0; i < n; i++){
				for(int j = i + 1; j < n; j++){
					for(Point2D p2d : Point2D.cross_ss(input[i], 1, input[j], 1)){
						//System.out.println(p2d);
						list.add(p2d);
					}
				}
			}
			
			int max = 1;
			for(Point2D p2d : list){
				int count = 0;
				
				for(int i = 0; i < n; i++){
					if(input[i].dist(p2d) <= 1 + Point2D.EPS){
						count++;
					}
				}
				//System.out.println(count);
				max = Math.max(max, count);
			}
			
			System.out.println(max);
		}
	}

}

class Point2D {
	public double x;
	public double y;
	
	public static final double EPS = 1e-11;
	
	public Point2D(double x, double y){
		this.x = x;
		this.y = y;
	}
	
	public Point2D(Point2D point){
		this.x = point.x;
		this.y = point.y;
	}
	
	public String toString(){
		return x + "," + y;
	}
	
	@Override
	public boolean equals(Object o){
		if(o instanceof Point2D){
			Point2D another = (Point2D) o;
			return this.x == another.x && this.y == another.y;
		}
		return false;
	}
	
	public Point2D add(double x, double y){
		return new Point2D(this.x + x, this.y + y);
	}
	
	public Point2D sub(double x, double y){
		return add(-x, -y);
	}
	
	public Point2D add(Point2D another){
		return add(another.x, another.y);
	}
	
	public Point2D sub(Point2D another){
		return sub(another.x, another.y);
	}
	
	public Point2D mul(double d){
		return new Point2D(this.x * d, this.y * d);
	}
	
	public Point2D div(double d){
		return new Point2D(this.x / d, this.y / d);
	}
	
	public double dot(double x, double y){
		return this.x * x + this.y * y; 
	}
	
	public double dot(Point2D another){
		return dot(another.x, another.y);
	}
	
	public double cross(double x, double y){
		return this.x * y - this.y * x; 
	}
	
	public double cross(Point2D another){
		return cross(another.x, another.y);
	}
	
	public double dist(double x, double y){
		return Math.sqrt((this.x - x)*(this.x - x) + (this.y - y) * (this.y - y));
	}
	
	public double dist(Point2D another){
		return dist(another.x, another.y);
	}
	
	public double dist_o(){
		return dist(0, 0);
	}
	
	public Point2D unit(){
		return div(dist_o());
	}
	
	public boolean pol(Point2D start, Point2D end){
		return end.sub(start).cross(this.sub(start)) < EPS;
	}
	
	public boolean pos(Point2D start, Point2D end){
		return (start.dist(this) + this.dist(end) < start.dist(end) + EPS);
	}
	
	public double pld(Point2D start, Point2D end){
		return Math.abs((end.sub(start).cross(this.sub(start)))/end.sub(start).dist_o());
	}
	
	public double psd(Point2D start, Point2D end){
		if(end.sub(start).dot(this.sub(start)) < EPS){
			return this.dist(start);
		}else if(start.sub(end).dot(this.sub(end)) < EPS){
			return this.dist(end);
		}else{
			return end.sub(start).cross(this.sub(start)) / end.dist(start);
		}
	}
	
	public static boolean intersect_s(Point2D a1, Point2D a2, Point2D b1, Point2D b2){
		return (a2.sub(a1).cross(b1.sub(a1)) * a2.sub(a1).cross(b2.sub(a1)) < EPS) && (b2.sub(b1).cross(a1.sub(b1)) * b2.sub(b1).cross(a2.sub(b1)) < EPS);
	}
	
	public static boolean insersect_l(Point2D a1, Point2D a2, Point2D b1, Point2D b2){
		return a1.sub(a2).cross(b1.sub(b2)) < EPS;
	}
	
	public static Point2D interpoint_s(Point2D a1, Point2D a2, Point2D b1, Point2D b2){
		Point2D b = b2.sub(b1);
		double d1 = Math.abs(b.cross(a1.sub(b1)));
		double d2 = Math.abs(b.cross(a2.sub(b1)));
		double t = d1 / (d1 + d2);
		Point2D a = a2.sub(a1), v = a.mul(t);
		return a1.add(v);
	}
	
	public static Point2D interpoint_l(Point2D a1, Point2D a2, Point2D b1, Point2D b2){
		Point2D a = a2.sub(a1);
		Point2D b = b2.sub(b1);
		double t = b.cross(b1.sub(a1)) / b.cross(a);
		Point2D v = a.mul(t);
		return a1.add(v);
	}
	
	public static Point2D[] cross_ss(Point2D p1, double r1, Point2D p2, double r2){
		double dis = p1.dist(p2);
		
		if(dis < EPS){
			return new Point2D[0]; //same
		}
		
		
		if(dis - EPS < r1 + r2 && dis + EPS > r1 + r2){
			Point2D tmp = p2.sub(p1);
			tmp = tmp.mul(r1 / tmp.dist_o());
			Point2D ret[] = new Point2D[1];
			ret[0] = p1.add(tmp);
			return ret;
		}else if(dis + EPS > r1 + r2){
			return new Point2D[0]; //out
		}
		
		double dis_m = Math.abs(r1-r2);
		
		
		if(dis_m + EPS > dis && dis_m - EPS < dis){
			Point2D tmp = null;
			if(r1 > r2){
				tmp = p2.sub(p1);
			}else{
				tmp = p1.sub(p2);
			}
			
			double min = Math.min(r1, r2);
			
			tmp = tmp.mul((min + tmp.dist_o()) / tmp.dist_o());
			
			Point2D ret[] = new Point2D[1];
			ret[0] = p1.add(tmp);
			return ret;
		}else if(dis_m + EPS > dis){
			return new Point2D[0]; //inner
		}else{
			Point2D ret[] = new Point2D[2];
			
			double theta = Math.acos((dis*dis + r1*r1 - r2*r2)/(2*dis*r1));
			double a = Math.atan2(p2.y-p1.y, p2.x-p1.x);
			
			ret[0] = new Point2D(r1*Math.cos(a+theta) + p1.x, r1*Math.sin(a+theta) + p1.y);
			ret[1] = new Point2D(r1*Math.cos(a-theta) + p1.x, r1*Math.sin(a-theta) + p1.y);
			return ret;
		}	
	}
	
	public void interpoint_lc(Point2D start , Point2D end , Point2D c , double r , Point2D ans[]){
		if(c.pld(start , end) > r + EPS) return;
		Point2D v= end.sub(start).unit();
		double delta=v.dot(start.sub(c))*v.dot(start.sub(c))-start.dist(c)*start.dist(c)+r*r;
		double t=-v.dot(start.sub(c));
		double s= Math.sqrt(delta);
		ans[0]=start.add(v.mul(t+s));
		ans[1]=start.add(v.mul(t+s));
	}
	
	public Point2D normal_vector(Point2D p,Point2D a,Point2D b){
		Point2D v= b.sub(a).unit();
		v = v.cross(p.sub(a)) > 0 ?  new Point2D(v.y,(-1)*v.x) : new Point2D((-1)*v.y , v.x);
		return v.mul(p.pld(a,b));
	}
	
	public double area(Point2D a,Point2D b,Point2D c){
		return Math.abs((c.sub(a).cross(b.sub(a)))*0.5);
	}
	
}