暴力枚举每个圆后面的所有圆
对这些圆每个与当前圆计算覆盖的弧度(有两个半径一个圆心距可以用余弦定理)
把算出来的这些弧度存起来
最后求个区间并,再计算剩余部分弧长
(摘自CreationAugust 的博客)
CODE
#include <set>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1005;
const double eps = 1e-10;
const double Pi = acos(-1.0);
inline double sqr(double x) { return x*x; }
struct Point {
double x, y;
inline Point(double _x=0, double _y=0): x(_x), y(_y){}
inline Point operator +(const Point &t)const { return Point(x + t.x, y + t.y); }
inline Point operator -(const Point &t)const { return Point(x - t.x, y - t.y); }
inline double operator *(const Point &t)const { return x*t.y - y*t.x; } //cross
inline double operator ^(const Point &t)const { return x*t.x + y*t.y; } //dot
inline double dist(const Point &t)const { return sqrt(sqr(x-t.x) + sqr(y-t.y)); }
inline double len() { return dist(Point(0, 0)); }
inline double angle() { return atan2(y, x); }
}O[MAXN];
int n; double r[MAXN];
set< pair<double, double> >S;
inline double calc(double a, double b, double c) {
return acos((sqr(a)+sqr(b)-sqr(c))/(2*a*b));
}
int main ()
{
int kase = 1;
//scanf("%d", &kase);
while(kase--) {
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%lf%lf%lf", &r[i], &O[i].x, &O[i].y);
double ans = 0;
for(int i = 1; i <= n; ++i) {
S.clear();
for(int j = i+1; j <= n; j++) {
double Len = O[i].dist(O[j]);
if(Len + r[i] > r[j] + eps && fabs(Len-r[i]) < r[j]){
double x = (O[j]-O[i]).angle(), y = calc(r[i], Len, r[j]);
double R = x + y, L = x - y;
if(L < -Pi) L += 2*Pi, R += 2*Pi;
if(R > Pi) S.insert(make_pair(L, Pi)), S.insert(make_pair(-Pi, R-2*Pi));
else S.insert(make_pair(L, R));
}
else if(Len + r[i] <= r[j] + eps)
S.insert(make_pair(-Pi, Pi));
}
set< pair<double, double> >::iterator it = S.begin();
double R = -Pi, sum = 0;
while(it != S.end()) {
if((*it).first > R) sum += (*it).first - R;
R = max(R, (*it).second); ++it;
}
sum += Pi - R;
ans += sum*r[i];
}
printf("%.3f
", ans);
}
}