题意:如题所示
这大概可以用辛普森积分求。。。?
定义函数f(x)为在这个位置上有效线段长度,有效线段就是直线被圆覆盖的区域
然后这不是个连续函数,为了减小误差,可以适当缩小圆与圆直接的距离,但不能影响答案
这样就差不多是个连续函数了。。。然后还可以去掉那些完全被包含的圆
预处理完以后在暴力辛普森积分
此题的eps要取到1E-13。。。并且常数不能太大
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 1010;
typedef double DB;
const DB EPS = 1E-13;
const DB INF = 1E16;
int cmp(const DB &x,const DB &y)
{
if (fabs(x - y) <= EPS) return 0;
return x < y ? -1 : 1;
}
struct Point{
DB x,y; Point(){}
Point(DB x,DB y): x(x),y(y){}
Point operator + (const Point &B) {return Point(x + B.x,y + B.y);}
Point operator - (const Point &B) {return Point(x - B.x,y - B.y);}
};
typedef Point Vector;
struct Circle{
Point o; DB r; Circle(){}
Circle(Point o,DB r): o(o),r(r){}
bool operator < (const Circle &B) const {return o.x - r < B.o.x - B.r;}
}c[maxn];
struct data{
DB w; int Num,typ; data(){}
data(DB w,int Num,int typ): w(w),Num(Num),typ(typ){}
bool operator < (const data &B) const
{
int d = cmp(w,B.w);
if (!d) return typ > B.typ;
return d < 0;
}
}D[maxn*2];
struct Range{
DB l,r; Range(){}
Range(DB l,DB r): l(l),r(r){}
bool operator < (const Range &B) const
{
int d = cmp(l,B.l);
if (!d) return r < B.r;
return d < 0;
}
}h[maxn*2];
int n,tp,sum;
bool bo[maxn];
DB last;
map <DB,DB> M;
DB Dot(Vector v1,Vector v2) {return v1.x * v2.x + v1.y * v2.y;}
DB Length(Vector v) {return sqrt(Dot(v,v));}
DB Cal(const DB &c,const DB &a) {return sqrt(c * c - a * a);}
bool Judge(Circle A,Circle B) {return cmp(A.r,Length(A.o - B.o) + B.r) >= 0;}
DB F(DB x)
{
if (M.count(x)) return M[x];
DB ret = 0; tp = 0;
for (int i = 1; i <= n; i++)
{
DB d = fabs(c[i].o.x - x);
if (cmp(c[i].r,d) <= 0) continue;
DB g = Cal(c[i].r,d);
h[++tp] = Range(c[i].o.y - g,c[i].o.y + g);
}
sort(h + 1,h + tp + 1);
int cur = 1; last = h[1].r;
for (int i = 2; i <= tp; i++)
{
int d = cmp(h[i].l,last);
if (d <= 0) last = max(last,h[i].r);
else
{
ret += last - h[cur].l;
cur = i; last = h[i].r;
}
}
ret += last - h[cur].l;
return M[x] = ret;
}
DB Calc(DB L,DB R)
{
DB A = (R - L) / 6.00;
DB B = F(L) + 4.00 * F((L + R) / 2.00) + F(R);
return A * B;
}
DB Simpson(DB L,DB R,DB now)
{
DB mid = (L + R) / 2.00,ret;
DB A = Calc(L,mid),B = Calc(mid,R);
if (!cmp(A + B,now)) ret = now;
else ret = Simpson(L,mid,A) + Simpson(mid,R,B);
M.erase(mid); return ret;
}
void Pre_Work(DB &L,DB &R)
{
for (int i = 1; i <= n; i++)
if (!bo[i]) c[++tp] = c[i];
n = tp; tp = 0; sort(c + 1,c + n + 1);
for (int i = 1; i <= n; i++)
{
L = min(L,c[i].o.x - c[i].r);
R = max(R,c[i].o.x + c[i].r);
D[++tp] = data(c[i].o.x - c[i].r,i,1);
D[++tp] = data(c[i].o.x + c[i].r,i,-1);
}
sort(D + 1,D + tp + 1); last = D[1].w;
for (int i = 1; i <= tp; i++)
{
if (!sum && D[i].typ == 1)
{
DB delta = D[i].w - last;
for (int j = D[i].Num; j <= n; j++) c[j].o.x -= delta;
}
if (sum == 1 && D[i].typ == -1) last = D[i].w;
sum += D[i].typ;
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
DB x,y,r;
scanf("%lf%lf%lf",&x,&y,&r);
c[i] = Circle(Point(x,y),r);
for (int j = 1; j < i; j++)
{
if (Judge(c[i],c[j])) bo[j] = 1;
else if (Judge(c[j],c[i])) bo[i] = 1;
}
}
DB L = INF,R = 0; Pre_Work(L,R);
printf("%.3lf\n",Simpson(L,R,Calc(L,R)));
//cerr << (DB)(clock()) / CLOCKS_PER_SEC << endl;
return 0;
}