Atcoder Regular Contest #011 D - きつねさんからの挑戦状

問題

日本語なので本文参照(http://arc011.contest.atcoder.jp/tasks/arc011_4


座標平面上で、n本の直線a[i]x + b[i]y + c[i] = 0および、
m個の点の座標と、ある整数Rが与えられる。


座標平面上の点(x, y)(|x|, |y|≦R)に対して、
最も近い直線との距離をa, 最も近い点との距離をbとする。
f(x, y) = a + b^2とするとき、
f(x, y)の最大値を求めよ。

制約条件

n, m≦16

方針

いるごさまの解説の通り。
http://topcoder.g.hatena.ne.jp/ir5/20130119


最大値を取るような点は、

  • 点と点の二等分線、
  • 正方形の辺
  • 角の二等分線

の交点のどれか。

交点はそんなに多くないので、全て列挙して、
それぞれでf(x, y)を求める。

ソースコード

int n, m, r;
int a[20], b[20], c[20];


int main()
{
	G ps;
	vector<L> ls;
	cin >> n >> m >> r;
	
	rep(i, n){
		cin >> a[i] >> b[i] >> c[i];
		if(a[i] == 0){
			ls.pb(L(P(0, -c[i] * 1.0 / b[i]), P(1, -c[i] * 1.0 / b[i])));
		}else if(b[i] == 0){
			ls.pb(L(P(-c[i] * 1.0 / a[i], 0), P(-c[i] * 1.0 / a[i], 1)));
		}
		else{
			ls.pb(L(P(0, -c[i] * 1.0 / b[i]), P(1, -(c[i] + a[i]) * 1.0 / b[i])));
		}
	}
	rep(i, m){
		int a, b;
		cin >> a >> b;
		ps.pb(P(a, b));
	}
	
	vector<L> l;
	G g;
	g.pb(P(-r, -r)); g.pb(P(r, -r));
	g.pb(P(r, r)); g.pb(P(-r, r));
	rep(i, 4) l.pb(L(g[i], g[(i + 1) % 4]));
	
	rep(i, n) rep(j, i){
		vector<L> v = bisectionLL(ls[i], ls[j]);
		rep(it, v.size()) l.pb(v[it]);
	}
	rep(i, m) rep(j, i) l.pb(bisectionPP(ps[i], ps[j]));
	
	double mx = -1;
	rep(i, l.size()) rep(j, i){
		if(!intersectLL(l[i], l[j])) continue;
		P p = crosspoint(l[i], l[j]);
		double mnp = INF, mnl = INF;
		
		if(p.real() < -r || p.real() > r) continue;
		if(p.imag() < -r || p.imag() > r) continue;
		
		rep(k, n) mnl = min(mnl, distanceLP(ls[k], p));
		rep(k, m) mnp = min(mnp, abs(p - ps[k]));
		mx = max(mx, mnl + mnp * mnp);
	}
	printf("%.9f\n", mx);
	
	return 0;
}