Problem:
Problem E: Immortal Jewels

English text is not available in this practice contest.

ある時ある貴族が，ある貧乏な国のおてんばで勇敢なお姫様に惚れ込み結婚を申し込んだ．お姫様は貴族にある条件を出した．その条件とは「不死の宝石」と呼ばれている宝石を大量に持ってくることであった．不死の宝石は，ある山の特定の場所でしか取ることができない非常に希少な宝石である．しかも大変壊れやすいため，採取するには特別な方法が必要だった．

不死の宝石は円形をしており，二次元空間上に複数存在している．この宝石を取るには，ある特別な金属の棒でそれらを吸着する必要がある．金属の棒は無限の長さを持つ直線であり，太さは無視することができる．宝石は一つ一つ異なる強さの磁力を持っており，金属がその磁力に反応するほど十分に近ければ宝石は吸着される．具体的には，金属と宝石の表面との距離を d ，宝石の磁力の強さを m としたとき，

0 ≤ d ≤ m

であれば宝石は金属に吸着される．逆に，金属の棒と宝石がその磁力よりも離れている場合は吸着できない．また，棒が少しでも宝石を貫通してしまった場合にも，その宝石が壊れてしまうため吸着できない．

例を見てみよう．下の図は二次元空間上に置かれた宝石の例である．宝石1から宝石6まであり，磁力はそれぞれ1, 0, 1, 1, 1, 2であるとする．

図 E-1: 宝石の配置例

上の図に加えて金属の棒を配置した例が下の図である．宝石を吸着した結果も表に示してある．この例の場合，宝石3は磁力の届く範囲より離れており，また宝石4は棒に貫通されているため吸着できないが，残りの4つは全て吸着することができる．

図 E-2: 金属の棒の配置例

宝石名

磁力

金属との距離

吸着できるか

宝石1

1

約0.21

できる

宝石2

0

0

できる

宝石3

1

約5.37

できない

宝石4

1

貫通している

できない

宝石5

1

約0.97

できる

宝石6

2

約0.53

できる

表 E-3: 吸着結果

貴族は全財産を注ぎ込み，特別な金属の棒を必死に探し求めた．しかしながら，この金属も非常に貴重であったため，結局たった一本しか入手することができなかった．したがって吸着のチャンスはただ一回しか無い．

あなたはある貴族に仕えるプログラマーである．あなたの仕事は，与えられた二次元上の宝石の配置に対して，金属の棒をうまく配置したときに，最大で何個の宝石を吸着することができるかを求めるプログラムを書くことである．

Input

入力は複数のデータセットから成り， 1つのデータセットは以下の形式で与えられる．

N

x1 y1 r1 m1

x2 y2 r2 m2

...

xN yN rN mN

データセットの最初の行は宝石の数 N (1 ≤ N ≤ 50) を表している．続く N 行の各行には4つの整数 xi, yi, ri, mi (-1000 ≤ xi, yi ≤ 1000, 1 ≤ ri ≤ 100, 0 ≤ mi ≤ 100) が記述されており，宝石の位置，大きさ，および磁力を表す．すなわち，宝石 i は中心を(xi, yi)とし半径が ri であるような円形をしており，その磁力は mi である．宝石は互いに重なり合うことは無い．

入力の終わりは，0のみからなる行で表される．

Output

各データセットについて， 一度に吸着することができる宝石の最大数を1行に出力せよ．

Sample Input

6
-2 -2 1 1
2 2 2 0
5 7 1 1
8 0 3 1
13 4 1 1
16 1 1 2
3
0 0 2 1
10 0 2 1
0 10 2 1
3
0 0 2 1
10 0 2 1
0 6 2 1
3
0 0 2 1
10 0 2 1
0 4 2 1
1
0 0 1 1
0

Output for the Sample Input

4
2
3
3
1

Solution in C++11 (judge verdict: Accepted)

#include <iostream>
#include <vector>
#include <array>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
struct Point {
	double x, y;
	double distance_from(const Point& that) const;
	Point move(const struct Vector& vec) const;
};
struct Vector {
	double dx, dy;
	Vector(const Point& to, const Point& from) : dx{ to.x - from.x }, dy{ to.y - from.y }{};
	Vector(const double _dx, const double _dy) :dx{ _dx }, dy{ _dy }{};
	Vector rotate(const struct Angle& angle) const;
	double length() const;
};
struct Line {
private:
	Line(const double _a, const double _b, const double _c) :a{ _a }, b{ _b }, c{ _c }{};
public:
	double a, b, c;
	Line(const Point& from, const Point& to) : a{ to.y - from.y }, b{ from.x - to.x }, c{ to.x * from.y - to.y * from.x }{};
	Line(const Point& point, const Vector& vec) : Line(point, Point{ point.x + vec.dx, point.y + vec.dy }){};
	double distance_from(const Point& that) const;
	Line shift_cathetus(const double dx) const;
};
struct Angle {
	double sin, cos;
	static Angle from_sin(const double sin);
	Angle operator+(const Angle& that) const;
	Angle operator-(const Angle& that) const;
	Angle operator-() const;
};
struct Circle {
	Point center;
	double radius;
	Circle change_radius(const double new_radius) const;
};
std::vector<Line> common_tangent(const Circle& a, const Circle& b) {
	std::vector<Line> result;
	const auto distance = a.center.distance_from(b.center);
	if (distance + a.radius <= b.radius || distance + b.radius <= a.radius) return result;
	const auto diff_angle = Angle::from_sin(std::abs(a.radius - b.radius) / distance);
	Vector vec(a.center, b.center);
	result.push_back(Line(b.center, vec.rotate(diff_angle)).shift_cathetus((a.radius > b.radius) ? b.radius : - b.radius));
	result.push_back(Line(b.center, vec.rotate(-diff_angle)).shift_cathetus((a.radius > b.radius) ? -b.radius : b.radius));
	if (distance >= a.radius + b.radius) {
		const auto add_angle = Angle::from_sin((a.radius + b.radius) / distance);
		result.push_back(Line(b.center, vec.rotate(add_angle)).shift_cathetus(-b.radius));
		result.push_back(Line(b.center, vec.rotate(-add_angle)).shift_cathetus(b.radius));
	}
	if (std::any_of(result.begin(), result.end(), [&a, &b](const Line& l) {return std::abs(l.distance_from(a.center) - a.radius) >= 1e-9 || std::abs(l.distance_from(b.center) - b.radius) >= 1e-9; })) {
		auto pos_b = b.center.move(vec.rotate(diff_angle));
		auto line_ba = Line(b.center, vec.rotate(diff_angle));
		auto pos_b_r = b.center.move(vec.rotate(-diff_angle));
		auto line_ba_r = Line(b.center, vec.rotate(-diff_angle));
		std::vector<std::vector<double>> distances;
		std::transform(result.begin(), result.end(), std::back_inserter(distances), [a, b](const Line& l) {return std::vector<double>{l.distance_from(a.center), l.distance_from(b.center)}; });
		throw "???";
	}
	return result;
}
struct Jewel {
	Circle circle;
	double magnet;
};
std::vector<Line> common_tangent(const Jewel& a, const Jewel& b) {
	std::vector<Line> result;
	for (const auto& line : common_tangent(a.circle, b.circle)) result.push_back(line);
	for (const auto& line : common_tangent(a.circle.change_radius(a.magnet + a.circle.radius), b.circle)) result.push_back(line);
	for (const auto& line : common_tangent(a.circle, b.circle.change_radius(b.magnet + b.circle.radius))) result.push_back(line);
	for (const auto& line : common_tangent(a.circle.change_radius(a.magnet + a.circle.radius), b.circle.change_radius(b.magnet + b.circle.radius))) result.push_back(line);
	return result;
}
int main() {
	while (true) {
		int n; std::cin >> n; if (n == 0) break;
		std::vector<Jewel> jewels(n); for (auto& j : jewels) std::cin >> j.circle.center.x >> j.circle.center.y >> j.circle.radius >> j.magnet;
		int max_correctable = 1;
		for (auto i = 0; i < n; ++i) {
			for (auto j = 0; j < i; ++j) {
				for (const auto line : common_tangent(jewels[i], jewels[j])) {
					int count = 2;
					for (auto k = 0; k < n; ++k) if (i != k && j != k) {
						auto distance = line.distance_from(jewels[k].circle.center) - jewels[k].circle.radius;
						if (0 <= distance && distance <= jewels[k].magnet) ++count;
					}
					max_correctable = std::max(max_correctable, count);
				}
			}
		}
		std::cout << max_correctable << '\n';
	}
}


double Line::distance_from(const Point& that) const
{
	return std::abs(a * that.x + b * that.y + c) / std::sqrt(a * a + b * b);
}

Line Line::shift_cathetus(const double length) const
{
	const auto len = std::sqrt(a * a + b * b);
	const auto dx = -a / len * length;
	const auto dy = b / len * length;
	return Line(a, b, c + b * dy - a * dx);
}

double Point::distance_from(const Point& that) const
{
	return Vector(*this, that).length();
}

Point Point::move(const Vector& vec) const
{
	return Point{ x + vec.dx, y + vec.dy };
}

Vector Vector::rotate(const Angle& angle) const
{
	return Vector{dx * angle.cos - dy * angle.sin, dx * angle.sin + dy * angle.cos};
}

double Vector::length() const
{
	return std::sqrt(dx * dx + dy * dy);
}

Angle Angle::from_sin(const double sin)
{
	return Angle{ sin, std::sqrt(1 - sin * sin) };
}

Angle Angle::operator+(const Angle& that) const
{
	return Angle{ sin * that.cos + cos * that.sin, cos * that.cos - sin * that.sin };
}

Angle Angle::operator-(const Angle& that) const
{
	return Angle{ sin * that.cos - cos * that.sin, cos * that.cos + sin * that.sin };
}

Angle Angle::operator-() const
{
	return Angle{ -sin, cos };
}

Circle Circle::change_radius(const double new_radius) const
{
	return Circle{ center, new_radius };
}