BOJ 415. 学姐的学弟

题目在这

题意:给出n个半径为1的圆的圆心坐标,求出所有圆的面积并

模板题目,直接粘代码吧,具体思路看这里

#include <algorithm>
#include <complex>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <utility>
#include <vector>
 
using namespace std;
 
const double EPS = 1e-8;
const double PI = acos(-1.0);
 
int dcmp(double x)
{
    if (fabs(x) < EPS) return 0;
    if (x > 0) return 1;
    else return -1;
}
 
inline double sqr(double x)
{
    return x * x;
}
 
struct point{
    double x, y;
    point(){}
    point(double a, double b) : x(a), y(b) {}
    void input(){
        scanf("%lf%lf", &x, &y);
    }
    double norm(){
        return sqrt(sqr(x) + sqr(y));
    }
    friend point operator+(const point &a, const point &b)
    {
        return point(a.x + b.x, a.y + b.y);
    }
    friend point operator - (const point &a, const point &b)
    {
        return point(a.x - b.x, a.y - b.y);
    }
    friend bool operator ==(const point &a, const point &b)
    {
        return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
    }
    friend point operator *(const point &a, const double &b)
    {
        return point(a.x * b, a.y * b);
    }
    friend point operator *(const double &a, const point &b)
    {
        return point(a * b.x , a * b.y);
    }
    friend point operator / (const point &a, const double &b)
    {
        return point(a.x / b, a.y / b);
    }
};
 
point rotate(const point &p, double cost, double sint)
{
    double x = p.x, y = p.y;
    return point(x * cost - y * sint, x * sint + y * cost);
}
 
pair<point, point> crosspoint(point ap, double ar, point bp, double br)
{
    double d = (ap - bp).norm();
    double cost = (ar * ar + d * d - br * br) / (2 * ar * d);
    double sint = sqrt(1.0 - cost * cost);
    point v = (bp - ap) / (bp - ap).norm() * ar;
    return make_pair(ap + rotate(v, cost, -sint), ap + rotate(v, cost, sint));
}
 
 
double cross(const point &a, const point & b){
    return a.x * b.y - a.y * b.x;
}
 
struct Circle{
    point p;
    double r;
    bool operator <(const Circle & o) const{
        if (dcmp(r - o.r) != 0) return dcmp(r - o.r) == -1;
        if (dcmp(p.x - o.p.x) != 0) return dcmp(p.x - o.p.x) == -1;
        return dcmp(p.y - o.p.y) == -1;
    }
    bool operator == (const Circle &o) const{
        return dcmp(r - o.r) == 0 && dcmp(p.x - o.p.x) == 0
            && dcmp(p.y - o.p.y) == 0;
    }
};
 
Circle c[110], tc[110];
int n,m;
struct Node{
    point p;
    double a;
    int d;
 
    Node(const point&p, double a, int d) :p(p), a(a), d(d){ }
    bool operator < (const Node & o) const{
        return a < o.a;
    }
};
 
double arg(point p)
{
    return arg(complex<double>(p.x, p.y));
}
 
double solve()
{
    n = 0;
    sort(tc, tc + m);
    m = unique(tc, tc + m) - tc;
    for (int i = m - 1; i >= 0; --i){
        bool ok = true;
        for (int j = i + 1; j < m; ++j){
            double d = (tc[i].p - tc[j].p).norm();
            if (dcmp(d - fabs(tc[i].r - tc[j].r)) <= 0){
                ok = false;
                break;
            }
        }
        if (ok) c[n++] = tc[i];
    }
    double ans = 0.0;
    for (int i = 0; i < n; ++i){
        vector<Node> event;
        point boundary = c[i].p + point(-c[i].r, 0);
        event.push_back(Node(boundary, -PI, 0));
        event.push_back(Node(boundary, PI, 0));
        for (int j = 0; j < n; ++j){
            if (i == j) continue;
            double d = (c[i].p - c[j].p).norm();
            if (dcmp(d - (c[i].r + c[j].r)) < 0){
                pair<point, point> ret = crosspoint(c[i].p, c[i].r,c[j].p,c[j].r);
                double x = arg(ret.first - c[i].p);
                double y = arg(ret.second - c[i].p);
                if (dcmp(x - y) > 0){
                    event.push_back(Node(ret.first, x, 1));
                    event.push_back(Node(boundary, PI, -1));
                    event.push_back(Node(boundary, -PI, 1));
                    event.push_back(Node(ret.second, y, -1));
                }
                else{
                    event.push_back(Node(ret.first, x, 1));
                    event.push_back(Node(ret.second, y, -1));
                }
            }
        }
        sort(event.begin(), event.end());
        int sum = event[0].d;
        for (int j = 1, sz = event.size(); j < sz; ++j){
            if (sum == 0){
                ans += cross(event[j - 1].p, event[j].p) / 2;
                double x = event[j - 1].a;
                double y = event[j].a;
                double area = c[i].r * c[i].r * (y - x) / 2;
                point v1 = event[j - 1].p - c[i].p;
                point v2 = event[j].p - c[i].p;
                area -= cross(v1, v2) / 2;
                ans += area;
            }
            sum += event[j].d;
        }
    }
    return ans;
}
 
int main(void)
{
    int T;
    scanf("%d", &T);
    while (T--){
        scanf("%d", &m);
        for (int i = 0; i < m; ++i){
            tc[i].p.input();
            tc[i].r = 1;
        }
        printf("%.5lf\n", solve());
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值