小谷の蟻の問題!
問題概要
の直方体の表面上で、1 つの頂点から最も遠い点への距離を求めよ。
下の図は 1 x 1 x 2 の例であり、とくに「小谷の蟻の問題」と呼ばれている。
制約
考えたこと
1 x 1 x 2 のときに、直方体の反対側の頂点が答えでないのが面白い。解説の図にあるように、基本的には 3 点の外心を求めることで求められる。
ただし、直方体の形状が立方体に近いときは、「直方体の反対側の頂点」が答えになる。たとえば、1 x 1 x 1 の立方体のときは、反対側の頂点が答えである。このような場合には、外心を求めようとしても失敗する。
具体的な式は、なんとこのページに書いてあった。
3 辺の長さを小さい順に として、こんな感じのコードで通った。つまり、
- 立方体に近い場合:直方体の反対側の頂点
- 立方体から遠い場合:3 点
の外心
との距離を求めることで通った。
if (B > C * (C * 2 - A) / (C * 2 + A)) { cout << sqrt(A * A + B * B + C * C + A * B * 2) << endl; } else { Point<DD> p(0, 0); Point<DD> q(A, A + C * 2); Point<DD> r(A + B + C, A + B + C); Circle<DD> circle = CircumscribedCircle(p, q, r); cout << circle.r << endl; }
コード
#include <bits/stdc++.h> using namespace std; //------------------------------// // 幾何の基本要素 (点, 線分, 円) //------------------------------// // basic settings long double EPS = 1e-10; // to be set appropriately constexpr long double PI = 3.141592653589793238462643383279502884L; long double torad(long double deg) {return (long double)(deg) * PI / 180;} long double todeg(long double ang) {return ang * 180 / PI;} // Point or Vector template<class DD> struct Point { // inner value DD x, y; // constructor constexpr Point() : x(0), y(0) {} constexpr Point(DD x, DD y) : x(x), y(y) {} // various functions constexpr Point conj() const {return Point(x, -y);} constexpr DD dot(const Point &r) const {return x * r.x + y * r.y;} constexpr DD cross(const Point &r) const {return x * r.y - y * r.x;} constexpr DD norm() const {return dot(*this);} constexpr long double abs() const {return sqrt(norm());} constexpr long double arg() const { if (this->eq(Point(0, 0))) return 0L; else if (x < -EPS && this->eq(Point(x, 0))) return PI; else return atan2((long double)(y), (long double)(x)); } constexpr bool eq(const Point &r) const {return (*this - r).abs() <= EPS;} constexpr Point rot90() const {return Point(-y, x);} constexpr Point rot(long double ang) const { return Point(cos(ang) * x - sin(ang) * y, sin(ang) * x + cos(ang) * y); } // arithmetic operators constexpr Point operator - () const {return Point(-x, -y);} constexpr Point operator + (const Point &r) const {return Point(*this) += r;} constexpr Point operator - (const Point &r) const {return Point(*this) -= r;} constexpr Point operator * (const Point &r) const {return Point(*this) *= r;} constexpr Point operator / (const Point &r) const {return Point(*this) /= r;} constexpr Point operator * (DD r) const {return Point(*this) *= r;} constexpr Point operator / (DD r) const {return Point(*this) /= r;} constexpr Point& operator += (const Point &r) { x += r.x, y += r.y; return *this; } constexpr Point& operator -= (const Point &r) { x -= r.x, y -= r.y; return *this; } constexpr Point& operator *= (const Point &r) { DD tx = x, ty = y; x = tx * r.x - ty * r.y; y = tx * r.y + ty * r.x; return *this; } constexpr Point& operator /= (const Point &r) { return *this *= r.conj() / r.norm(); } constexpr Point& operator *= (DD r) { x *= r, y *= r; return *this; } constexpr Point& operator /= (DD r) { x /= r, y /= r; return *this; } // friend functions friend ostream& operator << (ostream &s, const Point &p) { return s << '(' << p.x << ", " << p.y << ')'; } friend constexpr Point conj(const Point &p) {return p.conj();} friend constexpr DD dot(const Point &p, const Point &q) {return p.dot(q);} friend constexpr DD cross(const Point &p, const Point &q) {return p.cross(q);} friend constexpr DD norm(const Point &p) {return p.norm();} friend constexpr long double abs(const Point &p) {return p.abs();} friend constexpr long double arg(const Point &p) {return p.arg();} friend constexpr bool eq(const Point &p, const Point &q) {return p.eq(q);} friend constexpr Point rot90(const Point &p) {return p.rot90();} friend constexpr Point rot(const Point &p, long long ang) {return p.rot(ang);} }; // necessary for some functions template<class DD> constexpr bool operator < (const Point<DD> &p, const Point<DD> &q) { return (abs(p.x - q.x) > EPS ? p.x < q.x : p.y < q.y); } // Line template<class DD> struct Line : vector<Point<DD>> { Line(Point<DD> a = Point<DD>(0, 0), Point<DD> b = Point<DD>(0, 0)) { this->push_back(a); this->push_back(b); } friend ostream& operator << (ostream &s, const Line<DD> &l) { return s << '{' << l[0] << ", " << l[1] << '}'; } }; // Circle template<class DD> struct Circle : Point<DD> { DD r; Circle(Point<DD> p = Point<DD>(0, 0), DD r = 0) : Point<DD>(p), r(r) {} friend ostream& operator << (ostream &s, const Circle<DD> &c) { return s << '(' << c.x << ", " << c.y << ", " << c.r << ')'; } }; //------------------------------// // 点や線分の位置関係 //------------------------------// // arg sort // by defining comparison template<class DD> void arg_sort(vector<Point<DD>> &v) { auto sign = [&](const Point<DD> &p) -> int { if (abs(p.x) <= EPS && abs(p.y) <= EPS) return 0; else if (p.y < -EPS || (abs(p.y) <= EPS && p.x > EPS)) return -1; else return 1; }; auto cmp = [&](const Point<DD> &p, const Point<DD> &q) -> bool { if (sign(p) != sign(q)) return sign(p) < sign(q); return (abs(cross(p, q)) > EPS ? cross(p, q) > EPS : norm(p) < norm(q)); }; sort(v.begin(), v.end(), cmp); } // by calculating arg directly template<class DD> void arg_sort_direct(vector<Point<DD>> &v) { auto cmp = [&](const Point<DD> &p, const Point<DD> &q) -> bool { return (abs(arg(p) - arg(q)) > EPS ? arg(p) < arg(q) : norm(p) < norm(q)); }; sort(v.begin(), v.end(), cmp); } // 粗 // 1:a-bから見てcは左側(反時計回り)、-1:a-bから見てcは右側(時計回り)、0:一直線上 template<class DD> int simple_ccw (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) { if (cross(b-a, c-a) > EPS) return 1; if (cross(b-a, c-a) < -EPS) return -1; return 0; } // 精 // 1:a-bから見てcは左側(反時計回り)、-1:a-bから見てcは右側(時計回り) // 2:c-a-bの順に一直線上、-2:a-b-cの順に一直線上、0:a-c-bの順に一直線上 template<class DD> int ccw (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) { if (cross(b-a, c-a) > EPS) return 1; if (cross(b-a, c-a) < -EPS) return -1; if (dot(b-a, c-a) < -EPS) return 2; if (norm(b-a) < norm(c-a) - EPS) return -2; return 0; } // 点と三角形の包含関係(辺上については判定していない) template<class DD> bool is_contain (const Point<DD> &p, const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) { int r1 = simple_ccw(p, b, c), r2 = simple_ccw(p, c, a), r3 = simple_ccw(p, a, b); if (r1 == 1 && r2 == 1 && r3 == 1) return true; if (r1 == -1 && r2 == -1 && r3 == -1) return true; return false; } //------------------------------// // 線分の交差判定や距離計算 //------------------------------// template<class DD> int ccw_for_dis (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) { if (cross(b-a, c-a) > EPS) return 1; if (cross(b-a, c-a) < -EPS) return -1; if (dot(b-a, c-a) < -EPS) return 2; if (norm(b-a) < norm(c-a) - EPS) return -2; return 0; } template<class DD> Point<DD> proj(const Point<DD> &p, const Line<DD> &l) { DD t = dot(p - l[0], l[1] - l[0]) / norm(l[1] - l[0]); return l[0] + (l[1] - l[0]) * t; } template<class DD> Point<DD> refl(const Point<DD> &p, const Line<DD> &l) { return p + (proj(p, l) - p) * 2; } template<class DD> bool is_inter_PL(const Point<DD> &p, const Line<DD> &l) { return (abs(p - proj(p, l)) < EPS); } template<class DD> bool is_inter_PS(const Point<DD> &p, const Line<DD> &s) { return (ccw_for_dis(s[0], s[1], p) == 0); } template<class DD> bool is_inter_LL(const Line<DD> &l, const Line<DD> &m) { return (abs(cross(l[1] - l[0], m[1] - m[0])) > EPS || abs(cross(l[1] - l[0], m[0] - l[0])) < EPS); } template<class DD> bool is_inter_SS(const Line<DD> &s, const Line<DD> &t) { if (eq(s[0], s[1])) return is_inter_PS(s[0], t); if (eq(t[0], t[1])) return is_inter_PS(t[0], s); return (ccw_for_dis(s[0], s[1], t[0]) * ccw_for_dis(s[0], s[1], t[1]) <= 0 && ccw_for_dis(t[0], t[1], s[0]) * ccw_for_dis(t[0], t[1], s[1]) <= 0); } template<class DD> DD distance_PL(const Point<DD> &p, const Line<DD> &l) { return abs(p - proj(p, l)); } template<class DD> DD distance_PS(const Point<DD> &p, const Line<DD> &s) { Point h = proj(p, s); if (is_inter_PS(h, s)) return abs(p - h); return min(abs(p - s[0]), abs(p - s[1])); } template<class DD> DD distance_LL(const Line<DD> &l, const Line<DD> &m) { if (is_inter_LL(l, m)) return 0; else return distance_PL(m[0], l); } template<class DD> DD distance_SS(const Line<DD> &s, const Line<DD> &t) { if (is_inter_SS(s, t)) return 0; else return min(min(distance_PS(s[0], t), distance_PS(s[1], t)), min(distance_PS(t[0], s), distance_PS(t[1], s))); } //------------------------------// // 円や直線の交点 //------------------------------// template<class DD> Point<DD> proj_for_crosspoint(const Point<DD> &p, const Line<DD> &l) { DD t = dot(p - l[0], l[1] - l[0]) / norm(l[1] - l[0]); return l[0] + (l[1] - l[0]) * t; } template<class DD> vector<Point<DD>> crosspoint(const Line<DD> &l, const Line<DD> &m) { vector<Point<DD>> res; DD d = cross(m[1] - m[0], l[1] - l[0]); if (abs(d) < EPS) return vector<Point<DD>>(); res.push_back(l[0] + (l[1] - l[0]) * cross(m[1] - m[0], m[1] - l[0]) / d); return res; } template<class DD> vector<Point<DD>> crosspoint_SS(const Line<DD> &l, const Line<DD> &m) { if (is_inter_SS(l, m)) return crosspoint(l, m); else return vector<Point<DD>>(); } template<class DD> vector<Point<DD>> crosspoint(const Circle<DD> &e, const Circle<DD> &f) { vector<Point<DD>> res; DD d = abs(e - f); if (d < EPS) return vector<Point<DD>>(); if (d > e.r + f.r + EPS) return vector<Point<DD>>(); if (d < abs(e.r - f.r) - EPS) return vector<Point<DD>>(); DD rcos = (d * d + e.r * e.r - f.r * f.r) / (2.0 * d), rsin; if (e.r - abs(rcos) < EPS) rsin = 0; else rsin = sqrt(e.r * e.r - rcos * rcos); Point<DD> dir = (f - e) / d; Point<DD> p1 = e + dir * Point(rcos, rsin); Point<DD> p2 = e + dir * Point(rcos, -rsin); res.push_back(p1); if (!eq(p1, p2)) res.push_back(p2); return res; } template<class DD> vector<Point<DD>> crosspoint(const Circle<DD> &e, const Line<DD> &l) { vector<Point<DD>> res; Point<DD> p = proj_for_crosspoint(e, l); DD rcos = abs(e - p), rsin; if (rcos > e.r + EPS) return vector<Point<DD>>(); else if (e.r - rcos < EPS) rsin = 0; else rsin = sqrt(e.r * e.r - rcos * rcos); Point<DD> dir = (l[1] - l[0]) / abs(l[1] - l[0]); Point<DD> p1 = p + dir * rsin; Point<DD> p2 = p - dir * rsin; res.push_back(p1); if (!eq(p1, p2)) res.push_back(p2); return res; } //------------------------------// // 接線 //------------------------------// // tanline template<class DD> vector<Point<DD>> tanline(const Point<DD> &p, const Circle<DD> &c) { vector<Point<DD>> res; DD d = norm(p - c); DD l = d - c.r * c.r; if (l < -EPS) return res; if (l <= 0.0) l = 0.0; Point<DD> cq = (p - c) * (c.r * c.r / d); Point<DD> qs = rot90((p - c) * (c.r * sqrt(l) / d)); Point<DD> s1 = c + cq + qs, s2 = c + cq - qs; res.push_back(s1); res.push_back(s2); return res; } // common tanline, a and b must be different! // Line[0] is tangent point in a template<class DD> vector<Line<DD>> com_tanline(const Circle<DD> &a, const Circle<DD> &b) { vector<Line<DD>> res; // intersect if (abs(a - b) > abs(a.r - b.r) + EPS) { if (abs(a.r - b.r) < EPS) { Point<DD> dir = b - a; dir = rot90(dir * (a.r / abs(dir))); res.push_back(Line(a + dir, b + dir)); res.push_back(Line(a - dir, b - dir)); } else { Point<DD> p = a * -b.r + b * a.r; p = p * (1.0 / (a.r - b.r)); vector<Point<DD>> bs = tanline(p, a); vector<Point<DD>> as = tanline(p, b); for (int i = 0; i < min(as.size(), bs.size()); ++i) { res.push_back(Line(bs[i], as[i])); } } } // inscribed else if (abs(abs(a - b) - abs(a.r - b.r)) <= EPS) { Point<DD> dir = b - a; if (a.r > b.r) dir = dir * (a.r / abs(dir)); else dir = dir * (-a.r / abs(dir)); Point<DD> p = a + dir; res.push_back(Line(p, p + rot90(dir))); } // disjoint if (abs(a - b) > a.r + b.r + EPS) { Point<DD> p = a * b.r + b * a.r; p = p * (1.0 / (a.r + b.r)); vector<Point<DD>> bs = tanline(p, a); vector<Point<DD>> as = tanline(p, b); for (int i = 0; i < min(as.size(), bs.size()); ++i) { res.push_back(Line(bs[i], as[i])); } } // circumscribed else if (abs(abs(a - b) - (a.r + b.r)) <= EPS) { Point<DD> dir = b - a; dir = dir * (a.r / abs(dir)); Point<DD> p = a + dir; res.push_back(Line(p, p + rot90(dir))); } return res; } //------------------------------// // 多角形アルゴリズム //------------------------------// // 多角形の符号付面積 template<class DD> DD calc_area(const vector<Point<DD>> &pol) { DD res = 0.0; for (int i = 0; i < pol.size(); ++i) { res += cross(pol[i], pol[(i+1)%pol.size()]); } return res/2.0L; } // 点と多角形の包含関係 // 2: in, 1: on, 0: out template<class DD> int is_contain(const vector<Point<DD>> &pol, const Point<DD> &p) { int n = (int)pol.size(); int isin = 0; for (int i = 0; i < n; ++i) { Point<DD> a = pol[i] - p, b = pol[(i+1)%n] - p; if (a.y > b.y) swap(a, b); if (a.y <= 0 && b.y > 0) if (cross(a, b) < 0) isin = 1-isin; if (cross(a, b) == 0 && dot(a, b) <= 0) return 1; } if (isin) return 2; else return 0; } // 凸性判定 template<class DD> int ccw_for_isconvex (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) { if (cross(b-a, c-a) > EPS) return 1; if (cross(b-a, c-a) < -EPS) return -1; return 0; } template<class DD> bool is_convex(const vector<Point<DD>> &ps) { int n = (int)ps.size(); for (int i = 0; i < n; ++i) { if (ccw_for_isconvex(ps[i], ps[(i+1)%n], ps[(i+2)%n]) == -1) return false; } return true; } // 凸包 (一直線上の3点を含めない) template<class DD> vector<Point<DD>> convex_hull(vector<Point<DD>> &ps) { int n = (int)ps.size(); if (n == 1) return ps; vector<Point<DD>> res(2*n); auto cmp = [&](const Point<DD> &p, const Point<DD> &q) -> bool { return (abs(p.x - q.x) > EPS ? p.x < q.x : p.y < q.y); }; sort(ps.begin(), ps.end(), cmp); int k = 0; for (int i = 0; i < n; ++i) { if (k >= 2) { while (cross(res[k-1] - res[k-2], ps[i] - res[k-2]) < EPS) { --k; if (k < 2) break; } } res[k] = ps[i]; ++k; } int t = k+1; for (int i = n-2; i >= 0; --i) { if (k >= t) { while (cross(res[k-1] - res[k-2], ps[i] - res[k-2]) < EPS) { --k; if (k < t) break; } } res[k] = ps[i]; ++k; } res.resize(k-1); return res; } // 凸包 (一直線上の3点を含める) template<class DD> vector<Point<DD>> convex_hull_colinear(vector<Point<DD>> &ps) { int n = (int)ps.size(); if (n == 1) return ps; vector<Point<DD>> res(2*n); auto cmp = [&](const Point<DD> &p, const Point<DD> &q) -> bool { return (abs(p.x - q.x) > EPS ? p.x < q.x : p.y < q.y); }; sort(ps.begin(), ps.end(), cmp); int k = 0; for (int i = 0; i < n; ++i) { if (k >= 2) { while (cross(res[k-1] - res[k-2], ps[i] - res[k-2]) < -EPS) { --k; if (k < 2) break; } } res[k] = ps[i]; ++k; } int t = k+1; for (int i = n-2; i >= 0; --i) { if (k >= t) { while (cross(res[k-1] - res[k-2], ps[i] - res[k-2]) < -EPS) { --k; if (k < t) break; } } res[k] = ps[i]; ++k; } res.resize(k-1); return res; } // Convex Cut template<class DD> int ccw_for_convexcut (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) { if (cross(b-a, c-a) > EPS) return 1; if (cross(b-a, c-a) < -EPS) return -1; if (dot(b-a, c-a) < -EPS) return 2; if (norm(b-a) < norm(c-a) - EPS) return -2; return 0; } template<class DD> vector<Point<DD>> crosspoint_for_convexcut (const Line<DD> &l, const Line<DD> &m) { vector<Point<DD>> res; DD d = cross(m[1] - m[0], l[1] - l[0]); if (abs(d) < EPS) return vector<Point<DD>>(); res.push_back(l[0] + (l[1] - l[0]) * cross(m[1] - m[0], m[1] - l[0]) / d); return res; } template<class DD> vector<Point<DD>> convex_cut (const vector<Point<DD>> &pol, const Line<DD> &l) { vector<Point<DD>> res; for (int i = 0; i < pol.size(); ++i) { Point<DD> p = pol[i], q = pol[(i+1)%pol.size()]; if (ccw_for_convexcut(l[0], l[1], p) != -1) { if (res.size() == 0) res.push_back(p); else if (!eq(p, res[res.size()-1])) res.push_back(p); } if (ccw_for_convexcut(l[0], l[1], p) * ccw_for_convexcut(l[0], l[1], q) < 0) { vector<Point<DD>> temp = crosspoint_for_convexcut(Line(p, q), l); if (temp.size() == 0) continue; else if (res.size() == 0) res.push_back(temp[0]); else if (!eq(temp[0], res[res.size()-1])) res.push_back(temp[0]); } } return res; } // Voronoi Diagram // pol: outer polygon, ps: points // find the polygon nearest to ps[ind] template<class DD> Line<DD> bisector(const Point<DD> &p, const Point<DD> &q) { Point<DD> c = (p + q) / 2.0L; Point<DD> v = (q - p) * Point(0.0L, 1.0L); v = v / abs(v); return Line(c - v, c + v); } template<class DD> vector<Point<DD>> voronoi (const vector<Point<DD>> &pol, const vector<Point<DD>> &ps, int ind) { vector<Point<DD>> res = pol; for (int i = 0; i < ps.size(); ++i) { if (i == ind) continue; Line<DD> l = bisector(ps[ind], ps[i]); res = convex_cut(res, l); } return res; } //------------------------------// // 面積アルゴリズム //------------------------------// // 円と円の共通部分の面積 template<class DD> DD calc_common_area(const Circle<DD> &p, const Circle<DD> &q) { DD d = abs(p - q); if (d >= p.r + q.r - EPS) return 0; else if (d <= abs(p.r - q.r) + EPS) return min(p.r, q.r) * min(p.r, q.r) * PI; DD pcos = (p.r*p.r + d*d - q.r*q.r) / (p.r*d*2); DD pang = acosl(pcos); DD parea = p.r*p.r*pang - p.r*p.r*sin(pang*2)/2; DD qcos = (q.r*q.r + d*d - p.r*p.r) / (q.r*d*2); DD qang = acosl(qcos); DD qarea = q.r*q.r*qang - q.r*q.r*sin(qang*2)/2; return parea + qarea; } // 交点 template<class DD> int ccw_for_crosspoint_CS (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) { if (cross(b-a, c-a) > EPS) return 1; if (cross(b-a, c-a) < -EPS) return -1; if (dot(b-a, c-a) < -EPS) return 2; if (norm(b-a) < norm(c-a) - EPS) return -2; return 0; } template<class DD> bool isinterPS_crosspoint_CS(const Point<DD> &p, const Line<DD> &s) { return (ccw_for_crosspoint_CS(s[0], s[1], p) == 0); } template<class DD> Point<DD> proj_for_crosspoint_CS(const Point<DD> &p, const Line<DD> &l) { DD t = dot(p - l[0], l[1] - l[0]) / norm(l[1] - l[0]); return l[0] + (l[1] - l[0]) * t; } template<class DD> vector<Point<DD>> crosspoint_CS(const Circle<DD> &e, const Line<DD> &s) { vector<Point<DD>> res; Point<DD> p = proj_for_crosspoint_CS(e, s); DD rcos = abs(e - p), rsin; if (rcos > e.r + EPS) return vector<Point<DD>>(); else if (e.r - rcos < EPS) rsin = 0; else rsin = sqrt(e.r * e.r - rcos * rcos); Point<DD> dir = (s[1] - s[0]) / abs(s[1] - s[0]); Point<DD> p1 = p - dir * rsin; Point<DD> p2 = p + dir * rsin; if (isinterPS_crosspoint_CS(p1, s)) res.push_back(p1); if (isinterPS_crosspoint_CS(p2, s) && !eq(p1, p2)) res.push_back(p2); return res; } // 原点, 点 x, 点 y とで囲まれる領域の面積 (三角形 ver と扇型 ver) template<class DD> DD calc_element (const Point<DD> &x, const Point<DD> &y, DD r, bool triangle = true) { if (triangle) return cross(x, y) / 2; else { Point<DD> tmp = y * Point(x.x, -x.y); DD ang = atan2(tmp.y, tmp.x); return r * r * ang / 2; } } // 円 C と、三角形 ((0, 0), ia, ib) との共通部分の面積 template<class DD> DD calc_common_area (const Circle<DD> &c, const Point<DD> &ia, const Point<DD> &ib) { Point<DD> a = ia - c, b = ib - c; if (abs(a - b) < EPS) return 0; bool isin_a = (abs(a) < c.r + EPS); bool isin_b = (abs(b) < c.r + EPS); if (isin_a && isin_b) return calc_element(a, b, c.r, true); Circle<DD> oc(Point<DD>(0, 0), c.r); Line<DD> seg(a, b); auto cr = crosspoint_CS(oc, seg); if (cr.empty()) return calc_element(a, b, c.r, false); auto s = cr[0], t = cr.back(); return calc_element(s, t, c.r, true) + calc_element(a, s, c.r, isin_a) + calc_element(t, b, c.r, isin_b); } // 円 c と多角形 pol の共通部分の面積 template<class DD> DD calc_common_area(const Circle<DD> &c, const vector<Point<DD>> &pol) { DD res = 0; int n = (int)pol.size(); for (int i = 0; i < n; ++i) { res += calc_common_area(c, pol[i], pol[(i+1)%n]); } return res; } //------------------------------// // その他 //------------------------------// // 垂直二等分線 template<class DD> Line<DD> Bisector(const Point<DD> &p, const Point<DD> &q) { Point<DD> m = (p + q) / 2; Point<DD> x = m + rot90(q - p); return Line(m, x); } // 3 点を通る円 template<class DD> Circle<DD> CircumscribedCircle (const Point<DD> &p, const Point<DD> &q, const Point<DD> &r) { if (simple_ccw(p, q, r) == 0) return Circle<DD>(); Line<DD> pq = Bisector(p, q); Line<DD> pr = Bisector(p, r); vector<Point<DD>> centers = crosspoint(pq, pr); if (centers.empty()) return Circle<DD>(); Point<DD> center = centers[0]; DD radius = abs(center - p); return Circle(center, radius); } // AOJ 1460 - The Farthest Point void AOJ_1460() { cout << fixed << setprecision(10); using DD = long double; vector<DD> a(3); cin >> a[0] >> a[1] >> a[2]; sort(a.begin(), a.end()); DD A = a[0], B = a[1], C = a[2]; if (B > C * (C * 2 - A) / (C * 2 + A)) { cout << sqrt(A * A + B * B + C * C + A * B * 2) << endl; } else { Point<DD> p(0, 0); Point<DD> q(A, A + C * 2); Point<DD> r(A + B + C, A + B + C); Circle<DD> circle = CircumscribedCircle(p, q, r); cout << circle.r << endl; } } int main() { AOJ_1460(); }