【SPOJ CUIR】圆的面积并

【参考资料】

https://www.cnblogs.com/heisenberg-/p/6740654.html

 

【前置知识】

 

 

 


【题目见标题】

【题目大意】给 n 个圆,给其圆心何半径,求这 n 个圆覆盖的面积

【算法分析】

两种方法,一种是几何法,一种是自适应辛普森

 

之前在看自适应辛普森,结果卡时间卡的很不舒服,看底下几何法过的都闪电快如飞,于是决定用几何法

 

【几何法】

 通过计算圆和圆之间的交点,通过交点将圆的面积分为没有覆盖的圆和多次覆盖的多边形

然后将交点加入队列,极角排序后计算

通过对面积的计算,将结果变为仅仅计算一次

 

 

 

 

【代码】

 

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<vector>
  4 #include<algorithm>
  5 #include<map>
  6 #include<iostream>
  7 #include<complex>
  8 #include<queue>
  9 #include<stack>
 10 using namespace std;
 11 const double eps  = 1e-9;
 12 const double PI   = acos(-1.0);
 13 const int    MAXN = 1010000;
 14 int sgn(double x)
 15 {
 16     if (x < -eps)    return -1;
 17     if (x > eps)    return 1;
 18     return 0;
 19 }
 20 struct V
 21 {
 22     double x, y;
 23     double ang;
 24     V(double X = 0, double Y = 0)
 25     {
 26         //初始化
 27         x = X, y = Y;
 28     }
 29     bool operator ==(const V &b)
 30     {
 31         return sgn(x - b.x) && sgn(y - b.y);
 32     }
 33 
 34 };
 35 V operator +(V a, V b) { return V(a.x + b.x, a.y + b.y); }
 36 V operator -(V a, V b) { return V(a.x - b.x, a.y - b.y); }
 37 V operator *(V a, double b) { return V(a.x *b, a.y*b); }
 38 V operator /(V a, double b) { return V(a.x / b, a.y / b); }
 39 //叉积
 40 double cross(V a, V b)
 41 {
 42     return a.x*b.y - a.y*b.x;
 43 }
 44 typedef V P;
 45 //点积
 46 struct node
 47 {
 48     P p;
 49     double ang;
 50     int id;
 51     node(P a, double b, int c) :p(a), ang(b), id(c) {}
 52     bool operator<(node a)
 53     {
 54         return ang < a.ang;
 55     }
 56 };
 57 double dot(V a, V b)
 58 {
 59     return a.x*b.x + a.y*b.y;
 60 }
 61 struct L
 62 {
 63     P s, t;
 64     L() {}
 65     L(P a, P b):s(a), t(b) {}
 66 };
 67 typedef L  S;
 68 struct C
 69 {
 70     P p;
 71     double r;
 72     bool input()
 73     {
 74         return scanf("%lf%lf", &p.x, &p.y) != EOF;
 75     }
 76     bool operator<(const C &o)
 77     {
 78         if (sgn(r - o.r)     != 0)    return sgn(r - o.r) == -1;
 79         if (sgn(p.x - o.p.x) != 0)    return sgn(p.x - o.r) == -1;
 80         return sgn(p.y - o.p.y) == -1;
 81     }
 82     bool operator==(const C &o)
 83     {
 84         return sgn(r - o.r) == 0 && sgn(p.x - o.p.x)==0 && sgn(p.y - o.p.y)==0;
 85     }
 86 };
 87 double len(P a)
 88 {
 89     return sqrt(a.x*a.x + a.y*a.y);
 90 }
 91 C c[MAXN],arr[MAXN];
 92 int N;
 93 P rotate(P a, double cost, double sint)
 94 {
 95     double x = a.x, y = a.y;
 96     return P(x*cost - y * sint, x*sint + y * cost);
 97 }
 98 pair<P, P> crossP(P a, double r1, P b, double r2)
 99 {
100     double d = len(a - b);
101     //计算两圆心的距离
102     double cost = (r1*r1 + d * d - r2 * r2) / (2 * r1 *d);
103     //利用相似求出
104     double sint=(sqrt(1. - cost * cost));
105     P v = (b - a) / len(b - a) * r1;
106     return make_pair(a + rotate(v, cost,-sint), a + rotate(v, cost, sint));
107     
108 }
109 pair<P, P> crossP(C a, C b)
110 {
111     return crossP(a.p, a.r, b.p, b.r);
112     //方便填写函数的重载
113 }
114 double abs_t(double x)
115 {
116     if (x < -eps) return -x;
117     return x;
118 }
119 double arg(P a)
120 {
121     return arg(complex<double>(a.x, a.y));
122 }
123 vector<node> vec;
124 double solve()
125 {
126     int n = 0;
127     sort(c+1, c + 1 + N);
128     N = unique(c + 1, c + 1 + N) - (c + 1);
129     for (int i = N; i >= 1; i--)
130     {
131         bool flag = true;
132         for (int j = i + 1; j <= N; j++)
133         {
134             double d = len((c[i].p - c[j].p));
135             if (sgn(d - abs_t(c[i].r - c[j].r)) <= 0)
136             {
137                 flag = false; break;
138             }
139         }
140         if (flag) arr[++n] = c[i];
141         //去除被包含的圆
142     }
143     double ans = 0;
144     for (int i = 1; i <= n; i++)
145     {
146         vec.clear();
147         P bound = arr[i].p + P(-arr[i].r, 0);
148         vec.push_back(node(bound, -PI, 0));
149         vec.push_back(node(bound, PI , 0));
150         for (int j = 1; j <= n; j++)
151         {
152             if (i == j)    continue;
153             double d = len(arr[i].p - arr[j].p);
154             if (sgn(d - (arr[i].r + arr[j].r)) < 0)
155             {
156                 pair<P, P> ret = crossP(arr[i], arr[j]);
157                 //求取到两个圆的交点
158                 double x = arg(ret.first  - arr[i].p);
159                 //arg函数,求这个交点相对圆心的角度
160                 double y = arg(ret.second - arr[i].p);
161                 if (sgn(x - y) > 0)
162                 {
163                     vec.push_back(node(ret.first , x , 1 ));
164                     vec.push_back(node(bound     , PI, -1));
165                     vec.push_back(node(bound     , -PI, 1 ));
166                     vec.push_back(node(ret.second, y , -1));
167                 }
168                 else
169                 {
170                     vec.push_back(node(ret.first , x, 1 ));
171                     vec.push_back(node(ret.second, y, -1));
172                 }
173             }
174         }
175         sort(vec.begin(), vec.end());
176         int sum = vec[0].id;
177         for (int j = 1; j <(int)vec.size(); j++)
178         {
179             if (sum==0) 
180             {
181                 ans += cross(vec[j - 1].p, vec[j].p) / 2.;
182                 double x = vec[j - 1].ang;
183                 double y = vec[j].ang;
184                 double area = arr[i].r*arr[i].r*(y - x) / 2.;
185                 P v1 = vec[j - 1].p - arr[i].p;
186                 P v2 = vec[j].p - arr[i].p;
187                 area -= cross(v1, v2) / 2.;
188                 ans += area;
189             }
190             sum += vec[j].id;
191         }
192     }
193     return ans;
194 }
195 int main()
196 {
197     int m;
198     scanf("%d", &m);
199     N = 0;
200     for (int i = 1; i <= m; i++)
201     {
202         C tmp;
203         tmp.input();
204         scanf("%lf",&tmp.r);
205         if (sgn(tmp.r) != 0)
206             c[++N] = tmp;
207     }
208     printf("%.3f\n",solve());
209     return 0;
210 }

 

 

 

【自适应辛普森】

 利用积分的性质,计算每个圆弧

 

 

 

 

posted @ 2019-11-05 15:53  rentu  阅读(387)  评论(0编辑  收藏  举报