Description
有n个圆盘从天而降,后面落下的可以盖住前面的。求最后形成的封闭区域的周长。看下面这副图, 所有的红
色线条的总长度即为所求.
Input
第一行为1个整数n,N<=1000
接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标.
Output
最后的周长,保留三位小数
Sample Input
2
1 0 0
1 1 0
Sample Output
10.472
解题方法:看到题目成mengbier了。这个不是圆的周长交吧。。确实不是。。可是不会啊。。看了题解,感觉这个题其实很**。。对于每一个圆i,求出这个圆盘会被后面的每一个圆盘覆盖哪一段。对于一个圆,可以用-pi到pi的弧度表示区间,然后就可以用线段覆盖的方法求出区间被覆盖了多少了。 因此关键是对于两个圆盘i,j,如何求出i被覆盖的区间。首先对于两个圆的圆心x,y,可以求出向量(y-x)的atan2值,相当于与x轴正方向的夹角α,范围-pi到pi。然后根据余弦定理cos∠A=(b^2+c^2-a^2)/2bc,得到x的圆心到两圆的一个焦点的射线关于两圆连心线旋转角的余弦,然后用acos得到旋转角β,那么α±β就是对应的区间。注意边界问题,如果下界<-pi,就变成下界+2pi->pi,上界>pi同理。还有要判断圆相离的情况。。网上的题解看到这个题没卡精度。所以就没设eps了。。*一定要好好学习计几了(骗你的,我才不会)*
代码如下:
#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
const int N = 2005;
int n, cnt;
struct Point{
double x, y;
Point(){}
Point(double x, double y) : x(x), y(y) {}
bool operator <(const Point &rhs) const{
return x < rhs.x;
}
}s[N];
struct Circle{
Point o;
double r;
}a[N];
double sqr(double x){
return x*x;
}
double getdis(Point a, Point b){
return sqrt(sqr(b.x - a.x) + sqr(b.y - a.y));
}
void ins(double x, double y){
s[++cnt] = Point(x, y);
}
void getsegment(Circle u, Circle v, double dis){
double t1 = atan2(v.o.y - u.o.y, v.o.x - u.o.x);
double t2 = acos((sqr(dis) + sqr(u.r) - sqr(v.r)) / (2*dis*u.r));
Point t; t.x = t1 - t2; t.y = t1 + t2;
if(t.x >= -pi && t.y <= pi) ins(t.x, t.y);
else if(t.x < -pi){
ins(t.x + 2*pi, pi);
ins(-pi, t.y);
}else{
ins(t.x, pi);
ins(-pi, t.y - 2*pi);
}
}
double cal(){
double ans = 0;
double l = -10, r = -10;
sort(s + 1, s + cnt + 1);
for(int i = 1; i <= cnt; i++){
if(s[i].x > r){
ans += r - l;
l = s[i].x;
r = s[i].y;
}
else{
r = max(r, s[i].y);
}
}
ans += (r - l);
return 2*pi - ans;
}
int main(){
double ans = 0;
scanf("%d", &n);
for(int i = n; i >= 1; i--) scanf("%lf%lf%lf", &a[i].r, &a[i].o.x, &a[i].o.y);
for(int i = 1; i <= n; i++){
cnt = 0;
int j;
for(j = 1; j < i; j++){
double tmp = getdis(a[i].o, a[j].o);
if(a[j].r - a[i].r > tmp) break;
if(a[j].r + a[i].r > tmp && fabs(a[j].r - a[i].r) < tmp){
getsegment(a[i], a[j], tmp);
}
}
if(j == i) ans += a[i].r * cal();
}
printf("%.3f\n", ans);
return 0;
}