BZOJ 1043 下落的圆盘

Description

有n个圆盘从天而降,后面落下的可以盖住前面的。求最后形成的封闭区域的周长。看下面这副图, 所有的红色线条的总长度即为所求. 

Input

n ri xi y1 ... rn xn yn

Output

最后的周长,保留三位小数

Sample Input

2
1 0 0
1 1 0

Sample Output

10.472

HINT

数据规模

n<=1000

这道题目很好嘴巴,但是写起来有点儿蛋疼。

首先求出每个圆盘被他上面的圆盘覆盖的圆心角的度数α,用(2π-α)*c/2π即每个圆盘的周长答案,最后累加一遍答案即可。

那么圆心角要怎么求呢???

算出两个圆的交点肯定是没戏的(我推了很久的公式,还是退错了),后面想想,好像不用去求交点,可以直接用圆心角来计算区间。

如图若两圆C1,C2有交点(C2覆盖C1),则我们可以算出射线C1C2的极角θ。C1被C2所覆盖的圆心角的区间为[θ-α,θ+α]。但是注意,区间可能有越界的情况,比如说我们的区间是(-π,π]他的被覆盖的极角区间就是许多区间的并,但他可能和有[-1.2π,-0.7π],这时我们需要将区间拆开进行处理。比如此例中,我们拆成[-π,-0.7π]与[0.8π,π]。

还有一种情况就是C1的圆心在C2中,α的值为其补角。(自己画画图)。

  1 #include<iostream>
  2 #include<cmath>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstdlib>
  6 using namespace std;
  7
  8 #define pi (3.1415926535)
  9 #define esp (1e-6)
 10 #define maxn 2010
 11 int n; double ans;
 12
 13 inline bool equal(double a,double b) { return fabs(a - b) < esp; }
 14
 15 inline double qua(double a) { return a * a; }
 16
 17 inline bool dd(double a,double b) { if (equal(a,b)) return true; return a >= b; } //>=
 18
 19 inline bool xd(double a,double b) { if (equal(a,b)) return true; return a <= b; } //<=
 20
 21 struct NODE{ double x,y; };
 22 struct angle
 23 {
 24     double a1,a2;
 25     friend inline bool operator < (angle a,angle b)
 26     {
 27         if (!equal(a.a1,b.a1)) return xd(a.a1,b.a1);
 28         return xd(a.a2,b.a2);
 29     }
 30 }bac[maxn];
 31 struct CIR
 32 {
 33     double r,x,y;
 34     inline void read() { scanf("%lf %lf %lf",&r,&x,&y); }
 35     inline NODE mid() { return (NODE) {x,y}; }
 36     inline double calc(NODE p) { return atan2(p.y-y,p.x-x); }
 37     inline double C() { return 2*pi*r; }
 38 }cir[maxn];
 39 struct LINE
 40 {
 41     double a,b,c;
 42     inline double dis(NODE p) { return fabs(a*p.x+b*p.y+c)/sqrt(qua(a)+qua(b)); }
 43     inline double key(NODE p) { return p.x*a+p.y*b+c; }
 44 };
 45
 46 inline double dis(NODE a,NODE b) { return sqrt(qua(a.x-b.x) + qua(a.y-b.y)); }
 47
 48 inline bool have(CIR c1,CIR c2) { return dis(c1.mid(),c2.mid())<c1.r+c2.r; }
 49
 50 inline bool cat(CIR c1,CIR c2) { return xd(dis(c1.mid(),c2.mid()),fabs(c1.r-c2.r)); }
 51
 52 inline LINE cross(CIR c1,CIR c2) { return (LINE) {2*(c2.x-c1.x),2*(c2.y-c1.y),(qua(c2.r)-qua(c2.x)-qua(c2.y))-(qua(c1.r)-qua(c1.x)-qua(c1.y))}; }
 53
 54 inline void work()
 55 {
 56     int tot,i,j; double rest,p,q,a,b,now; LINE l;
 57     for (i = n;i;--i)
 58     {
 59         tot = 0; rest = 0; now = 0;
 60         for (j = i+1;j <= n;++j)
 61         {
 62             if (cat(cir[i],cir[j]))
 63             {
 64                 if (cir[i].r > cir[j].r) continue;
 65                 else break;
 66             }
 67             if (have(cir[i],cir[j]))
 68             {
 69                 p = cir[i].calc(cir[j].mid()) + pi;
 70                 l = cross(cir[i],cir[j]);
 71                 q = l.dis(cir[i].mid());
 72                 q = acos(q/cir[i].r);
 73                 if (cir[i].r < cir[j].r&&l.key(cir[i].mid())*l.key(cir[j].mid()) > 0)
 74                     q = pi - q;
 75                 a = p - q; b = p + q;
 76                 if (dd(a,0) && xd(b,2*pi))
 77                     bac[++tot] = (angle) {a,b};
 78                 else if (a < 0)
 79                 {
 80                     bac[++tot] = (angle) {a+2*pi,2*pi};
 81                     bac[++tot] = (angle) {0,b};
 82                 }
 83                 else
 84                 {
 85                     bac[++tot] = (angle) {a,2*pi};
 86                     bac[++tot] = (angle) {0,b-2*pi};
 87                 }
 88             }
 89         }
 90         if (j != n+1) continue;
 91         sort(bac+1,bac+tot+1);
 92         for (int j = 1;j <= tot;++j)
 93         {
 94             if (bac[j].a1 > now)
 95             {
 96                 rest += bac[j].a1 - now;
 97                 now = bac[j].a2;
 98             }
 99             else now = max(now,bac[j].a2);
100         }
101         rest += 2*pi - now;
102         ans += rest/(2*pi) * cir[i].C();
103     }
104 }
105
106 int main()
107 {
108     freopen("1043.in","r",stdin);
109     freopen("1043.out","w",stdout);
110     scanf("%d",&n);
111     for (int i = 1;i <= n;++i) cir[i].read();
112     work();
113     printf("%.3lf",ans);
114     fclose(stdin); fclose(stdout);
115     return 0;
116 }

时间: 2024-10-10 10:11:48

BZOJ 1043 下落的圆盘的相关文章

bzoj 1043 下落的圆盘 —— 求圆心角、圆周长

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1043 求出每个圆没被覆盖的长度即可: 特判包含和相离的情况,注意判包含时 i 包含 j 和 j 包含 i 是不同的情况: 然后考虑相交,可以算出被覆盖的那段圆弧所对的圆心角,用一个 [0,2π] 的角度区间维护没被覆盖的部分: 所求的角度是对于一条"基准线"而言的,所以首先要求出圆心连线对于"基准线"的角度,因为知道两个圆心,可以利用 atan2(y,x) 求

bzoj1043[HAOI2008]下落的圆盘 计算几何

1043: [HAOI2008]下落的圆盘 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1598  Solved: 676[Submit][Status][Discuss] Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求.  Input 第一行为1个整数n,N<=1000接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标

【BZOJ1043】[HAOI2008]下落的圆盘 几何

[BZOJ1043][HAOI2008]下落的圆盘 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 题解:对于每个圆,我们枚举它后面的

BZOJ 1043 HAOI2008 下落的圆盘 计算几何

题目大意:n个圆盘依次下落.求终于能看到的轮廓线面积 円盘反对! 让我们一起团结起来! 赶走円盘! 咳咳.非常神的一道题 今天去看了题解和白书才搞出来-- 首先我们倒着做 对于每一个圆盘处理出在它之后落下的圆盘和它的覆盖区间 然后求一个区间并就能算出这个圆盘的可见弧长 然后就是相交部分怎么求的问题了 首先两个圆必须相交 然后作圆心1到圆心2的向量 用atan2求出极角 然后利用余弦定理求出两个交点和圆心连线的夹角就可以 注意区间不在[0,2π]的部分要切割成还有一个区间 处理起来事实上不是非常麻

【BZOJ】1043: [HAOI2008]下落的圆盘(计算几何+贪心)

http://www.lydsy.com/JudgeOnline/problem.php?id=1043 唯一让我不会的就是怎么求圆的周长并QAAQ... 然后发现好神!我们可以将圆弧变成$[0, 2 \pi ]$的直线! 然后一定要注意!起点是$(1, 0)$(单位圆) 首先学了余弦定理... 在三角形ABC中 $$cos A=\frac{|AB|^2+|AC|^2-|BC|^2}{2|AB| |AC|}$$ 证明很简单... $$\begin{align}|{BC}|^2 & = \vec{

BZOJ 1043: [HAOI2008]下落的圆盘

Description 求几个圆交起来的周长..\(n\leqslant 10^3\) Solution 计算几何. 圆圆求交.. Code /************************************************************** Problem: 1043 User: BeiYu Language: C++ Result: Accepted Time:520 ms Memory:1308 kb *******************************

BZOJ 1043 HAOI 2008 下落的圆盘 计算几何

题目大意:给出一些圆盘,他们按照时间顺序相互覆盖,问最后的到的图形的可见圆周的周长是多少. 前言:円盘反对!让我们一起团结起来!赶走円盘! 思路:对于每一个圆盘,只要扫描在它后面出现的圆与它交的部分的并,总周长-相交的并就是剩下能看见的圆周的长度,然后累加到答案中. 对于两个圆的交,我们可以用一个有序数对(x,y)以弧度为单位来表示,这样所有的xy都在0~2π区间之内.求角度就利用余弦定理,见下图: ∠EAC就是我们要求的角.由于我们知道|AE|和|EC|分别是两个圆的半径,|AC|是圆心的距离

【BZOJ 1043】【HNOI 2008】下落的圆盘 判断圆相交+线段覆盖

计算几何真的好暴力啊. #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define max(a,b) (a) > (b) ? (a) : (b) #define N 1003 using namespace std; const double Pi = acos(-1); inline int dcmp(double x) {return (fabs(x)

BZOJ1043:[HAOI2008]下落的圆盘——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=1043 Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红 色线条的总长度即为所求. Input 第一行为1个整数n,N<=1000 接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标. Output 最后的周长,保留三位小数 Sample Input 2 1 0 0 1 1 0 Sample Out