题解:[HAOI2008]下落的圆盘
时空限制:1000ms / 128MB
原题链接:
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
题解
两页的爆蛋记录(来自蒟蒻的无助)。
orz千古神犇wzp一眼秒题。
这种题一定要耐心地做(初中数学老师一直这么对我说)。
首先,我们来看其简化版:
我们把\(\odot B\)覆盖在\(\odot A\)上,我们发现我们需要求出\(\angle A\)的度数。我的方法是连结\(CB,AB,BD,AB\)(如图)。我们发现\(\triangle ABC\cong\triangle ABD\),又在\(\triangle ABC\)中,由余弦定理得:\(\cos A=\frac{{AC}^2 + {AB}^2 - BC^2}{2\times AB \times AC}\)于是我们就得到了\(\angle A\)。
恭喜你过了样例。
double dist = get_dist(A, B);
if(dist > A.r+B.r || A.r + dist < B.r)
return;
if(dist + B.r < A.r)//完全被覆盖
{
gaif = true;//标记直接跳出
return;
}
double alpha = acos((sqr(B.r)+sqr(dist)-sqr(A.r))/(B.r*dist*2.));
那么如果有多个圆呢?
我们发现,对于\(\odot A\)来说,\(EF\)被覆盖了两次,但我们之能减一次。于是我们就想到了:对于每个圆,枚举盖在其上面的圆,算出每个覆盖“线段”的左右端点,然后进行一次线段覆盖将其合并。最后,我们只要算出没有被覆盖到的线段长度即可。
我们用极角来表示圆上点的位置,这样我们就可以进行线段覆盖操作了。
如图,\(AE\)平行\(x\)轴,我们以算出\(AC\)的斜率,加个\(\arctan\)即可求出\(\angle CAE\),然后\(\angle EAD\)、\(\angle BAE\)均可求出。
于是理论上的问题就全部解决了。
对于极角还有一个小细节:
由于我们在线段求并时只容许有\(1\)到\(2\pi\)的弧度,因此,对于两个“交点”\(l,r\),我们需要作出以下特判:
- \(l<0\)且\(r<0\)时,我们要把\(l\)与\(r\)均加上\(2\pi\);
- \(l<0\)且\(r>0\)时,我们插入\([l+2\pi,2\pi],[0,r]\)两段;
- \(l<2\pi\)且\(r>2\pi\)时,我们插入\([l,2\pi],[0,r-2\pi]\)两段。
具体代码实现如下:
//const double pi2 = 2*pi
if(jiao1 < 0 && jiao2 < 0)//这句话花了我一页的提交
{
jiao1 += pi2, jiao2 += pi2;
}
if(jiao1 >= 0 && jiao2 <= pi2)
cha(jiao1, jiao2);
else
{
if(jiao1 < 0)
{
cha(jiao1+pi2, pi2);
cha(0, jiao2);
}
else
{
cha(jiao1, pi2);
cha(0, jiao2-pi2);
}
}
整体代码
//代码有些冗长,大佬勿喷
//蒟蒻无毒,请放心食用
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 10005;
const double pi = 3.1415926535897932;
const double pi2 = 2*pi;
struct Point
{
double x, y;
};
inline double sqr(double x)
{
return x*x;
}
inline double get_dist(Point x, Point y)
{
return sqrt(sqr(x.x-y.x) + sqr(x.y-y.y));
}
struct Circle
{
Point O;
double r;
} c[maxn];
inline double get_dist(Circle x, Circle y)
{
return get_dist(x.O, y.O);
}
int n;
struct Fugai
{
double l, r;
inline bool operator < (const Fugai& other) const
{
return l < other.l;
}
} fugai[maxn];
int nown;
inline void cha(double l, double r)
{
fugai[++nown] = (Fugai)
{
l, r
};
}
bool gaif = false;//gaif = true表示该圆盘被上面的大圆盘完全覆盖
inline void jiao(Circle A, Circle B)
{
double dist = get_dist(A, B);
if(dist > A.r+B.r || A.r + dist < B.r)//没有任何覆盖
return;
if(dist + B.r < A.r)//如果被一个大圆盘完全覆盖,直接跳出
{
gaif = true;
return;
}
double alpha = acos((sqr(B.r)+sqr(dist)-sqr(A.r))/(B.r*dist*2.));//上图中的角CAD
double beta = atan2(B.O.y-A.O.y, A.O.x-B.O.x);//上图中的角CAE
double jiao1 = beta-alpha;//线段覆盖中的l
double jiao2 = beta+alpha;//线段覆盖中的r
if(jiao1 < 0 && jiao2 < 0)//对极角的一些特判
{
jiao1 += pi2, jiao2 += pi2;
}
if(jiao1 >= 0 && jiao2 <= pi2)
cha(jiao1, jiao2);
else
{
if(jiao1 < 0)
{
cha(jiao1+pi2, pi2);
cha(0, jiao2);
}
else
{
cha(jiao1, pi2);
cha(0, jiao2-pi2);
}
}
}
inline double get_ans()
{
double ans = 0;
sort(fugai+1, fugai+nown+1);
double lastr = fugai[1].l;
for(int i = 1; i <= nown; ++i)
{
if(lastr >= fugai[i].r)
continue;
if(fugai[i].l > lastr)
ans += fugai[i].r - fugai[i].l;
else
ans += fugai[i].r - lastr;
lastr = fugai[i].r;
}
return ans;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%lf%lf%lf", &c[i].r, &c[i].O.x, &c[i].O.y);
double ans = 0;
for(int i = n; i; --i)
{
nown = 0;
for(int j = n; j > i; --j)//枚举所有该圆盘之后的圆盘
{
jiao(c[j], c[i]);
if(gaif)
break;
}
if(gaif)
gaif = false;
else
ans += (pi2-get_ans())*c[i].r;
nown = 0;
}
printf("%.3f", ans);
return 0;
}
题解:[HAOI2008]下落的圆盘的更多相关文章
- 【BZOJ1043】[HAOI2008]下落的圆盘 几何
[BZOJ1043][HAOI2008]下落的圆盘 Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求. ...
- bzoj1043[HAOI2008]下落的圆盘 计算几何
1043: [HAOI2008]下落的圆盘 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1598 Solved: 676[Submit][Stat ...
- luogu P2510 [HAOI2008]下落的圆盘
LINK:下落的圆盘 计算几何.n个圆在平面上编号大的圆将编号小的圆覆盖求最后所有没有被覆盖的圆的边缘的总长度. 在做这道题之前有几个前置知识. 极坐标系:在平面内 由极点 极轴 和 极径组成的坐标系 ...
- BZOJ1043:[HAOI2008]下落的圆盘——题解(配图片)
http://www.lydsy.com/JudgeOnline/problem.php?id=1043 Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周 ...
- BZOJ 1043 HAOI2008 下落的圆盘 计算几何
题目大意:n个圆盘依次下落.求终于能看到的轮廓线面积 円盘反对! 让我们一起团结起来! 赶走円盘! 咳咳.非常神的一道题 今天去看了题解和白书才搞出来-- 首先我们倒着做 对于每一个圆盘处理出在它之后 ...
- 【bzoj1043】[HAOI2008]下落的圆盘 计算几何
题目描述 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求. 输入 第一行为1个整数n,N<=1000接下来n行每行3个实 ...
- 【BZOJ】1043: [HAOI2008]下落的圆盘(计算几何基础+贪心)
http://www.lydsy.com/JudgeOnline/problem.php?id=1043 唯一让我不会的就是怎么求圆的周长并QAAQ... 然后发现好神!我们可以将圆弧变成$[0, 2 ...
- [HAOI2008]下落的圆盘
Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红 色线条的总长度即为所求. Input 第一行为1个整数n,N<=100 ...
- bzoj1043 [HAOI2008]下落的圆盘
Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求. Input 第一行为1个整数n,N<=1000 ...
随机推荐
- Alpha冲刺(7/10)——2019.4.29
作业描述 课程 软件工程1916|W(福州大学) 团队名称 修!咻咻! 作业要求 项目Alpha冲刺(团队) 团队目标 切实可行的计算机协会维修预约平台 开发工具 Eclipse 团队信息 队员学号 ...
- Web Api 实现新建功能接口
ResultModel类 是一个结果类 public class ResultModel { /// <summary> /// 返回结果状态 /// </summary> p ...
- 30分钟用 Laravel 实现一个博客
介绍 Laravel 是一款 MVC架构. 目前最流行的 PHP框架. Laravel的优点在于: 丰富的composer类库支持, 优雅的代码, 未来的主流框架(目前市场占有率最高的框架) Lara ...
- 『7.5 NOIP模拟赛题解』
T1 Gift Description 人生赢家老王在网上认识了一个妹纸,然后妹纸的生日到了,为了表示自己的心 意,他决定送她礼物.可是她喜爱的东西特别多,然而他的钱数有限,因此他想 知道当他花一 ...
- JavaWeb学习路线图(2020年最新版)
Java基础 做java开发,java基础是最需要下功夫的一项.在校招时最注重的就是基础,拿不出像样的项目没关系,但是基础万万不可不牢固. 想要基础扎实,看书沉淀是必须的,有一些编程基础的同学推荐阅读 ...
- syntax error near unexpected token 脚本报错误解决
hadoop老师给了一个shell文件,在windows里面瞅了一眼然后在ubuntu环境下运行就报错了.看了一些博客,用vim -b filename查看的时候发现每一行的末尾都多了一个^M.... ...
- C#读写修改设置调整UVC摄像头画面-伽玛
有时,我们需要在C#代码中对摄像头的伽玛进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像 ...
- Java 8 New Features
What's New in JDK 8 https://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html Java Pla ...
- Maven中 jar包冲突原理与解决办法
Maven中jar包冲突是开发过程中比较常见而又令人头疼的问题,我们需要知道 jar包冲突的原理,才能更好的去解决jar包冲突的问题.本文将从jar包冲突的原理和解决两个方面阐述Maven中jar包冲 ...
- java中创建线程的3种方法
1.继承Thread类优点:可以直接使用Thread类中的方法,代码比较简单.缺点:继承Thread类之后不能继承其他类. 2.实现Runable接口优点:实现接口,比影响继承其他类或实现接口.缺点: ...