mayoko’s diary

プロコンとかいろいろ。

AOJ 1132 Circle and Points

解法

ある円が答えだったとします。この円を少し動かしても, この円が最適であることに変わりはありません。この円を適当に動かして, 初めてある点とぶつかったとき, 円をこの点からはみ出さないように動かすと, もう一つの点とぶつかります。

ということで, 円としては, 2 点を通るような円のみを考えれば良いです。

2 点 pnt[i], pnt[j] を通る円の中心はどうなるのかを考えます。この円の中心は, pnt[i], pnt[j] からの距離がどちらも 1 になっているようなものなので, pnt[i], pnt[j] を結ぶ線分の垂直二等分線上にあります。後は適当にホイしましょう。

typedef long double Real;

Real eps = 1e-9;

Real add(Real a, Real b) {
    if (abs(a+b) < eps * (abs(a)+abs(b))) return 0;
    return a+b;
}

bool equal(Real a, Real b) {
    return add(a, -b) == 0;
}

struct P {
    Real x, y;
    P() {}
    P(Real x, Real y) : x(x), y(y) {}
    P operator+(P p) const {return P(add(x, p.x), add(y, p.y));}
    P operator-(P p) const {return P(add(x, -p.x), add(y, -p.y));}
    P operator*(Real d) const {return P(x*d, y*d);}
    Real dot(P p) const {return add(x*p.x, y*p.y);} // 内積
    Real det(P p) const {return add(x*p.y, -y*p.x);} // 外積
    Real dist(P p) const {return sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));} // 距離
    void normalize() {Real d = sqrt(x*x+y*y); x /= d; y /= d;} // 正規化
    bool operator<(const P& rhs) const {
        if (x != rhs.x) return x < rhs.x;
        return y < rhs.y;
    }
    bool operator==(const P& rhs) const {
        return equal(x, rhs.x) && equal(y, rhs.y);
    }
};
const int MAXN = 333;
P pnt[MAXN];
int N;

int calc(P center) {
	int ret = 0;
	for (int i = 0; i < N; i++) {
		P vec = pnt[i]-center;
		if (vec.dot(vec) < 1+eps) {
			ret++;
		}
	}
	return ret;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    while (cin >> N) {
    	if (N==0) break;
    	for (int i = 0; i < N; i++) 
    		cin >> pnt[i].x >> pnt[i].y;
    	int ans = 1;
    	for (int i = 0; i < N; i++) for (int j = i+1; j < N; j++) {
    		if (pnt[i].dist(pnt[j]) > 2) continue;
    		// diff を取る
    		P vec = pnt[j]-pnt[i];
    		// vec に垂直なベクトルを取る
    		P n = P(vec.y, -vec.x);
    		n.normalize();
    		vec = vec*0.5;
    		Real len = sqrt(1-vec.dot(vec));
    		P cand1 = pnt[i] + vec + n*len;
    		P cand2 = pnt[i] + vec - n*len;
    		ans = max(ans, calc(cand1));
    		ans = max(ans, calc(cand2));
    	}
    	cout << ans << endl;
    }
    return 0;
}