mayoko’s diary

プロコンとかいろいろ。

Educational Codeforces Round 2 D. Area of Two Circles' Intersection

解法

イデアだけなら大学受験の典型ですね(手計算でとけるかは置いておいて)

2 つの円の半径を r, R (r <= R), 2 つの円の距離を d とします。

  • R+r <= d なら, 円は交わらないので答えは 0
  • R-r >= d なら, 円 r は 円 R に完全に含まれるので, 答えは pi*r^2
  • それ以外の場合は, 辺の長さがそれぞれ R, r, d の三角形が中に出来て, 辺 r に対する角度 phi と, 辺 R に対する角度 theta が, 余弦定理によってわかります。これが分かれば, 交わっている部分の面積は, 2つの「扇型 - 三角形」の形で書けるので, 面積を求められます。
Real add(Real a, Real b) {
    if (abs(a+b) < eps * (abs(a)+abs(b))) return 0;
    return a+b;
}

bool equal(Real a, Real b) {
    return add(a, -b) == 0;
}
struct P {
    Real x, y;
    P() {}
    P(Real x, Real y) : x(x), y(y) {}
    P operator+(P p) const {return P(add(x, p.x), add(y, p.y));}
    P operator-(P p) const {return P(add(x, -p.x), add(y, -p.y));}
    P operator*(Real d) const {return P(x*d, y*d);}
    Real dot(P p) const {return add(x*p.x, y*p.y);} // 内積
    Real det(P p) const {return add(x*p.y, -y*p.x);} // 外積
    Real dist(P p) const {return sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));} // 距離
    void normalize() {Real d = sqrt(x*x+y*y); x /= d; y /= d;} // 正規化
    bool operator<(const P& rhs) const {
        if (x != rhs.x) return x < rhs.x;
        return y < rhs.y;
    }
    bool operator==(const P& rhs) const {
        return equal(x, rhs.x) && equal(y, rhs.y);
    }
};

const Real pi = acosl(-1);
Real square(Real x) {return x*x;}

Real calc(Real r, Real theta) {
    Real ret = r*r*theta;
    ret -= 2*(r*sinl(theta)) * (r*cosl(theta)) / 2;
    return ret;
}

int main() {
    Real x1, y1, R;
    Real x2, y2, r;
    cin >> x1 >> y1 >> R;
    cin >> x2 >> y2 >> r;
    P p1(x1, y1), p2(x2, y2);
    if (R < r) {
        swap(R, r);
        swap(p1, p2);
    }
    Real d = p1.dist(p2);
    Real ans;
    if (d >= R+r) {
        ans = 0;
    } else if (R >= d+r) {
        ans = r*r*pi;
    } else {
        Real theta = acosl((R*R+d*d-r*r)/(2*R*d));
        Real phi = acosl((r*r+d*d-R*R)/(2*r*d));
        ans = calc(R, theta);
        ans += calc(r, phi);
    }
    cout << setprecision(12) << ans << endl;
    return 0;
}