SPOJ 8073 The area of the union of circles (圆并入门)

Sphere Online Judge (SPOJ) - Problem CIRU

【求圆并的若干种算法,圆并扩展算法】_AekdyCoin的空间_百度空间

  参考AekdyCoin的圆并算法解释,根据理解写出的代码。圆并这么多题中,最基础一题。

  操作如下:

(1)对一个圆,获得所有与其他圆的交点作为时间戳。

  a.如果这个圆不被其他任何圆覆盖,这个圆直接保留。

  b.如果Case中有两个完全重合的圆,可以保留标号小(或大)的圆,也只保留这一个。

(2)每经过一个时间戳就对计数器加减,如果计数器从0变1,加上这段圆弧和对应的三角形。

(3)所有这样的圆独立计算,最后求出的面积累加即可。

代码如下(1y):

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iomanip>
  5 #include <iostream>
  6 #include <algorithm>
  7 
  8 using namespace std;
  9 
 10 const double PI = acos(-1.0);
 11 const double EPS = 1e-8;
 12 inline int sgn(double x) { return (x > EPS) - (x < -EPS);}
 13 template<class T> T sqr(T x) { return x * x;}
 14 typedef pair<double, double> Point;
 15 #define x first
 16 #define y second
 17 Point operator + (Point a, Point b) { return Point(a.x + b.x, a.y + b.y);}
 18 Point operator - (Point a, Point b) { return Point(a.x - b.x, a.y - b.y);}
 19 Point operator * (Point a, double p) { return Point(a.x * p, a.y * p);}
 20 Point operator / (Point a, double p) { return Point(a.x / p, a.y / p);}
 21 
 22 inline double cross(Point a, Point b) { return a.x * b.y - a.y * b.x;}
 23 inline double dot(Point a, Point b) { return a.x * b.x + a.y * b.y;}
 24 inline double angle(Point a) { return atan2(a.y, a.x);}
 25 inline double veclen(Point a) { return sqrt(dot(a, a));}
 26 
 27 struct Circle {
 28     Point c;
 29     double r;
 30     Circle() {}
 31     Circle(Point c, double r) : c(c), r(r) {}
 32     Point point(double p) { return Point(c.x + r * cos(p), c.y + r * sin(p));}
 33     void get() { scanf("%lf%lf%lf", &c.x, &c.y, &r);}
 34 } ;
 35 
 36 bool ccint(Circle a, Circle b, double &a1, double &a2) { // ips for Circle-a (anti-clockwise p1->p2)
 37     double d = veclen(a.c - b.c);
 38     double r1 = a.r, r2 = b.r;
 39     if (sgn(d - r1 - r2) >= 0) return 0;
 40     if (sgn(fabs(r1 - r2) - d) >= 0) return 0;
 41     double da = acos((sqr(d) + sqr(r1) - sqr(r2)) / (2 * d * r1));
 42     double ang = angle(b.c - a.c);
 43     a1 = ang - da, a2 = ang + da;
 44     return 1;
 45 }
 46 
 47 const int N = 1111;
 48 Circle cir[N];
 49 
 50 inline double gettri(Point o, Point a, Point b) { return cross(a - o, b - o) / 2;}
 51 inline double getarc(Circle o, double a, double b) { return (b - a) * sqr(o.r) / 2 - gettri(o.c, o.point(a), o.point(b));}
 52 
 53 typedef pair<double, int> Event;
 54 Event ev[N << 2];
 55 
 56 bool inside(int a, int n) {
 57     double d, r1, r2;
 58     for (int i = 0; i < n; i++) {
 59         if (i == a) continue;
 60         d = veclen(cir[i].c - cir[a].c);
 61         r1 = cir[i].r, r2 = cir[a].r;
 62         if (sgn(r1 - r2) == 0 && sgn(fabs(r1 - r2) - d) == 0) {
 63             if (i > a) return 1;
 64             continue;
 65         }
 66         if (sgn(r1 - r2) >= 0 && sgn(fabs(r1 - r2) - d) >= 0) return 1;
 67     }
 68     return 0;
 69 }
 70 
 71 double getarea(int a, int n) {
 72     if (inside(a, n)) return 0;
 73     Circle &c = cir[a];
 74     double ret = 0;
 75     double a1, a2;
 76     Point p1, p2;
 77     int tt = 0;
 78     for (int i = 0; i < n; i++) {
 79         if (i == a) continue;
 80         if (ccint(c, cir[i], a1, a2)) {
 81             if (a2 > PI) ev[tt++] = Event(a1, 1), ev[tt++] = Event(PI, -1), ev[tt++] = Event(-PI, 1), ev[tt++] = Event(a2 - 2 * PI, -1);
 82             else if (a1 < -PI) ev[tt++] = Event(a1 + 2 * PI, 1), ev[tt++] = Event(PI, -1), ev[tt++] = Event(-PI, 1), ev[tt++] = Event(a2, -1);
 83             else ev[tt++] = Event(a1, 1), ev[tt++] = Event(a2, -1);
 84         }
 85     }
 86     if (tt == 0) return PI * sqr(c.r);
 87     sort(ev, ev + tt);
 88     int cnt = 0;
 89     double last = -PI;
 90     for (int i = 0; i < tt; i++) {
 91         double cur = ev[i].x;
 92         if (ev[i].y == 1 && cnt == 0) ret += getarc(c, last, cur) + cross(c.point(last), c.point(cur)) / 2;
 93         cnt += ev[i].y;
 94         last = cur;
 95     }
 96     ret += getarc(c, last, PI) + cross(c.point(last), c.point(PI)) / 2;
 97     return ret;
 98 }
 99 
100 double work(int n) {
101     double ret = 0;
102     for (int i = 0; i < n; i++) ret += getarea(i, n);
103     return ret;
104 }
105 
106 int main() {
107     int n;
108     while (~scanf("%d", &n)) {
109         for (int i = 0; i < n; i++) cir[i].get();
110         printf("%.3f\n", work(n));
111     }
112     return 0;
113 }
View Code

 

——written by Lyon

 

转载于:https://www.cnblogs.com/LyonLys/p/spoj_ciru_Lyon.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值