TopCoder SRM 326 Div1 Medium InscribedTriangles
問題
半径5の円がある。
この円周上から三点を、それぞれのx軸から半時計周りに見た角度が区間[angleFrom[i], angleTo[i]]のいずれかに入っているように選ぶ。
このとき、三角形ABCの面積の最大値を求めよ。
制約条件
angleFromとangleToの要素の数は等しい
angleToの要素の数≦30
角度は1/1000度単位で与えられる。
方針
A, B, Cのうち、点Aはどこかの区間の端点であるとして一般性を失わない。
点Bの属する区間を決める。
すると面積に関する三分探索が出来るので、面積を最大にするBを三分探索により求める。
Cは、A, Bを決めると、(A + B) / 2または(A + B) / 2 + 180度に一番近い点が良いので、
候補は2 * 区間の数個程度に絞れる。
ソースコード
double a, b; int n; vi to, from; inline double area(double c){ P A = polar(1.0, a * PI / 180000); P B = polar(1.0, b * PI / 180000); P C = polar(1.0, c * PI / 180000); B -= A; C -= A; return abs(B.real() * C.imag() - B.imag() * C.real()) * 12.5; } inline double calc(double x){ b = x; double cc = (a + b) / 2; double res = 0; rep(i, 2){ rep(j, n){ if(from[j] <= cc && cc <= to[j]){ res = max(res, area(cc)); continue; } double da = abs(cc - to[j]); double db = abs(cc - from[j]); if(da > 180000) da = 360000 - da; if(db > 180000) db = 360000 - db; if(da < db) res = max(res, area(to[j])); else res = max(res, area(from[j])); } cc += 180000; if(cc >= 360000) cc -= 360000; } return res; } class InscribedTriangles { public: double findLargest(vector <int> angleFrom, vector <int> angleTo) { while(1){ bool update = 0; rep(i, angleTo.size()) rep(j, angleTo.size()) if(i != j){ if(angleFrom[i] <= angleFrom[j] && angleTo[j] <= angleTo[i]){ angleFrom.erase(angleFrom.begin() + j); angleTo.erase(angleTo.begin() + j); goto NEXT; } } rep(i, angleTo.size()) rep(j, angleTo.size()) if(i != j){ if(angleFrom[j] <= angleTo[i] && angleTo[i] <= angleTo[j]){ angleTo[i] = angleTo[j]; angleTo.erase(angleTo.begin() + j); angleFrom.erase(angleFrom.begin() + j); goto NEXT; } } if(!update) break; NEXT:; } to = angleTo; from = angleFrom; sort(all(to)); sort(all(from)); n = to.size(); double ans = 0; rep(i, n) rep(j, 2){ a = j ? to[i] : from[i]; rep(k, n){ double lo = from[k], hi = to[k], l, r; rep(it, 100){ l = (lo * 2 + hi) / 3; r = (lo + hi * 2) / 3; if(calc(l) < calc(r)) lo = l; else hi = r; } ans = max(ans, calc(l)); } } return ans; } };