TopCoder SRM Div1 Medium CentersOfSymmetry
問題
n本の相異なる直線が与えられる。
n本の直線の集合の、点対称の中心の個数を求めよ。
無限にある場合は-1を返せ。
制約条件
n≦50
直線はその直線が通る2点の座標により与えられる。
点は全て格子点である。
方針
まずは点対称の中心が無限にあるかを見る。
平行な直線a, bについて、
その真ん中の線上の点がその候補。
その中で適当な座標が無理数な点を取ってやって、
その点に関して全ての点を対称移動してやって、直線の集合が元と一致するかを見る。
次に対称中心が1点の場合。
直線同士の交点は、これもまた点対称になっているはず。
なので、直線の交点の全ての中心が対称中心の候補。
この点に関して全ての点を対称移動して、直線の集合が元と一致するか見る。
ソースコード
struct L : public vector<P> { double a, b, c; L(const P &p1, const P &p2) { push_back(p1); push_back(p2); double dx = p2.real() - p1.real(); double dy = p2.imag() - p1.imag(); a = dx; b = -dy; c = -p1.imag() * dx + p1.real() * dy; if(a) b /= a, c /= a, a = 1; else a /= b, c /= b, b = 1; } bool operator==(const L &o)const{ return abs(a - o.a) < EPS && abs(b - o.b) < EPS && abs(c - o.c) < EPS; } bool operator<(const L &o)const{ if(abs(a - o.a) > EPS) return a < o.a; if(abs(b - o.b) > EPS) return b < o.b; return c + EPS < o.c; } }; P ref(const P &p, const P &o){ return 2.0 * o - p; } class CentersOfSymmetry { public: int lineConfigurations(vector <int> x1, vector <int> y1, vector <int> x2, vector <int> y2) { int n = x1.size(); if(n == 1) return -1; set<L> s; vector<P> p1, p2; vector<P> cs; rep(i, n) p1.pb(P(x1[i], y1[i])), p2.pb(P(x2[i], y2[i])); rep(i, n) s.insert(L(p1[i], p2[i])); rep(i, n) rep(j, i){ if(!intersectLL(L(p1[i], p2[i]), L(p1[j], p2[j]))){ P q1 = (p1[i] + p1[j]) * 0.5, q2 = (p2[i] + p2[j]) * 0.5; if(abs(q1 - q2) < EPS){ q1 = (p1[i] + p2[j]) * 0.5; q2 = (p2[i] + p1[j]) * 0.5; } P o = q1 * sqrt(2.0) + q2 * (1 - sqrt(2.0)); set<L> ss; rep(k, n){ P r1 = ref(p1[k], o), r2 = ref(p2[k], o); ss.insert(L(r1, r2)); } if(s == ss) return -1; } else{ P p = crosspoint(L(p1[i], p2[i]), L(p1[j], p2[j])); cs.pb(p); } } if(cs.empty()) return 0; P o; rep(i, cs.size()) o += cs[i]; o *= 1.0 / cs.size(); set<L> ss; rep(i, n){ P r1 = ref(p1[i], o), r2 = ref(p2[i], o); ss.insert(L(r1, r2)); } return s == ss ? 1 : 0; } };