TopCoder SRM 332 Div1 Medium RestoringPolygon
問題
y軸に平行な線分がいくつか与えられる。
これらのうち、好きなものと、任意のx軸に平行な線分を使って、辺が全て座標軸に平行で、
自己交差のない単純多角形を描きたい。
描ける多角形のうち、もっとも辺の多いものの辺の数はいくつか、求めよ。
制約条件
線分の個数≦16
方針
使う線分を2^n通り試す。
使う線分の集合を決めると、
x座標ごとに区切って見たときに、同じx座標の点は、
y座標が小さい順に2個ずつ線分で結ばれることになる。
すなわち、描かれる多角形の候補が一意に定まる。
あとはこの候補がvalidであるか(自己交差があったりしないか)をチェックすればいい。
y座標の順にソートするのを忘れててはまった。
ソースコード
struct cmp{ double x; cmp(double x) : x(x){} bool operator()(const L &s, const L &t){ bool fs = abs(s[0].real() - x) < EPS || abs(s[1].real() - x) < EPS; bool ft = abs(t[0].real() - x) < EPS || abs(t[1].real() - x) < EPS; if(fs != ft) return fs; const P a = abs(s[0].real() - x) < EPS ? s[0] : s[1]; const P b = abs(t[0].real() - x) < EPS ? t[0] : t[1]; return a.imag() < b.imag(); } }; bool ok(const vector<L> ls){ int n = ls.size(); bool use[50] = {}; vector<P> ps; ps.pb(ls[0][0]); ps.pb(ls[0][1]); use[0] = 1; rep(k, n - 1){ bool ok = 0; rep(i, n) if(!use[i]) rep(j, 2) if(abs(ps.back() - ls[i][j]) < EPS){ ps.pb(ls[i][1 - j]); use[i] = 1; ok = 1; goto NEXT; } NEXT: if(!ok) return 0; } if(abs(ps.back() - ps[0]) > EPS) return 0; ps.pop_back(); rep(i, n) rep(j, i - 2){ if(i == n - 1 && j == 0) continue; if(intersectSS(L(ps[i], ps[(i + 1) % n]), L(ps[j], ps[j + 1]))) return 0; } return 1; } class RestoringPolygon { public: int restore(vector <int> x1, vector <int> x2, vector <int> y) { int n = y.size(); int ans = 0; rep(i, 1 << n) if(i){ vector<L> ls, tate; set<int> xs; rep(j, n) if(i & 1 << j){ ls.pb(L(P(x1[j], y[j]), P(x2[j], y[j]))); xs.insert(x1[j]); xs.insert(x2[j]); } each(j, xs){ sort(all(ls), cmp(*j)); int pp = -1, k = 0; for(; k < ls.size(); k++){ int p = 0; for(; p < 2 && abs(ls[k][p].real() - *j) > EPS; p++); if(p >= 2) break; if(k % 2 == 1) tate.pb(L(ls[k - 1][pp], ls[k][p])); pp = p; } if(k % 2) goto FAIL; } ls.insert(ls.end(), all(tate)); if(ok(ls)) ans = max(ans, (int)ls.size()); FAIL:; } return ans; } };