【BZOJ-1502】月下柠檬树 计算几何 + 自适应Simpson积分
1502: [NOI2005]月下柠檬树
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 1017 Solved: 562
[Submit][Status][Discuss]
Description
Input
文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度)。第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的高度和每层的高度。第3行包含n个实数r1,r2,…,rn,表示柠檬树每层下底面的圆的半径。上述输入文件中的数据,同一行相邻的两个数之间用一个空格分隔。输入的所有实数的小数点后可能包含1至10位有效数字。
Output
输出1个实数,表示树影的面积。四舍五入保留两位小数。
Sample Input
10.0 10.00 10.00
4.00 5.00
Sample Output
HINT
1≤n≤500,0.3
Source
Solution
一道计算集合比较蛋疼的题目
当时的正解应该是分类讨论+特判很多东西再直接求面积,但是发现这题非常适合辛普森积分所以就直接上了
那么先是辛普森积分的公式:
对于某些不易计算曲线的一种近似方法,能自动调整精度,但误差较大(比较平滑的曲线非常适合)
具体的计算流程就是,计算[l,mid]以及[mid,r]与直接计算[l,r]的结果相比较,如果近似则返回[l,r]即可,否则可以分别递归细化
这种做法非常好卡,一种最简单的卡法:这样一开始就会直接返回,然而递归下去才能求的更精确的值
---------------------------------------------------分割线---------------------------------------------------
首先我们考虑这题的投影,圆投下来,和之前完全一样,所以投影本质是一些圆和他们的公切线组成的图形求面积
发现其实是轴对称图形,所以可以考虑直接利用扫描线+自适应Simpson来做
扫描线被覆盖部分的长度的函数F(x)在这个图形的区间中是连续的,因此不必考虑将整个图形拆成若干个一坨一坨的图形再求积分,少了不少细节。
无论扫描线在何处,它被覆盖的部分也是永远是连续的,因此可以暴力找每个圆是否和扫描线有交,每条公切线段是否和扫描线有交,然后取扫描线被覆盖长度的最大值即可
那么至于求公切线,比较简单,给出详细方法:
首先我们得到:$l=C_{i+1}.O.x-C_{i+1}.O.x$
那么我们可以算出:$sin\alpha = (R-r)/l$,$cos\alpha = \sqrt{1-sin^2\alpha}$(考虑从$C_{i+1}.O$向$R$做垂线)
那么可以算出切点:
$C_{i}.A=(C_{i}.O.x+R*sin\alpha,R*cos\alpha)$
$C_{i+1}.A=(C_{i+1}.O.x+r*sin\alpha,r*cos\alpha)$
这题的细节比较麻烦,注意特判圆被另一个圆直接覆盖的情况
---------------------------------------------------分割线---------------------------------------------------
这道题还需要注意一下精度问题
个人测试:eps=1e-5是可行最优
eps=1e-12 --> 5s
eps=1e-8 --> 1s
eps=1e-5 --> 0.5s
eps=1e-3/-4 --> Wrong_Answer
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define MAXN 1010 double alpha; int N,num; #define INF 1e12 #define eps 1e-5 struct Point { double x,y; Point (double X=0,double Y=0) {x=X; y=Y;} }; struct Circle { double r; Point c; Circle(Point C=(Point){0,0},double R=0) {c=C; r=R;} }C[MAXN]; struct Line { Point s,t; double k,b; Line(Point S=(Point){0,0},Point T=(Point){0,0}) { s=S,t=T; if (s.x>t.x) swap(s,t); k=(s.y-t.y)/(s.x-t.x); b=s.y-k*s.x; } double f(double x) {return k*x+b;} }l[MAXN]; int dcmp(double x) {if (fabs(x)<eps) return 0; return x<0? -1:1;} double F(double x) { double re=0; for (int i=1; i<=N; i++) //枚举圆是否与扫描线有交 { double d=fabs(x-C[i].c.x); if (dcmp(d-C[i].r)>0) continue; double len=2*sqrt(C[i].r*C[i].r-d*d); re=max(re,len); } for (int i=1; i<=num; i++) //枚举公切线if (x>=l[i].s.x && x<=l[i].t.x) re=max(re,2*l[i].f(x)); return re; } //利用扫描线去判断 double Calc(double l,double r) {double mid=(l+r)/2; return (F(l)+F(r)+F(mid)*4)*(r-l)/6;} double Simpson(double l,double r,double now) { double mid=(l+r)/2; double x=Calc(l,mid),y=Calc(mid,r); if (!dcmp(now-x-y)) return now; else return Simpson(l,mid,x)+Simpson(mid,r,y); } void Solve() { double L=INF,R=-INF; for (int i=1; i<=N+1; i++) L=min(L,C[i].c.x-C[i].r),R=max(R,C[i].c.x+C[i].r); // printf("%lf\n%lf\n",L,R); for (int i=1; i<=N; i++) { double d=C[i+1].c.x-C[i].c.x; if (dcmp(d-fabs(C[i].r-C[i+1].r))<0) continue; //特判小圆被大圆覆盖的情况double sina=(C[i].r-C[i+1].r)/d,cosa=sqrt(1-sina*sina); l[++num]=(Line){(Point){C[i].c.x+C[i].r*sina,C[i].r*cosa},(Point){C[i+1].c.x+C[i+1].r*sina,C[i+1].r*cosa}}; } printf("%.2lf\n",Simpson(L,R,Calc(L,R))); } int main() { scanf("%d%lf",&N,&alpha); double h,r; for (int i=1; i<=N+1; i++) scanf("%lf",&h), C[i]=(Circle){((Point){(h/tan(alpha))+C[i-1].c.x,0}),0}; for (int i=1; i<=N; i++) scanf("%lf",&r),C[i].r=r; // for (int i=1; i<=N+1; i++) // printf("%d %.2lf %.2lf\n",i,C[i].c.x,C[i].r); Solve(); return 0; }
晚上颓这道‘模版题’简直不要太爽,来个人求一下我的心里阴影面积吧QAQ
转载于:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5676841.html
【BZOJ-1502】月下柠檬树 计算几何 + 自适应Simpson积分相关推荐
- bzoj 1502月下柠檬树 Simpson积分
关键点是,水平的圆投影到水平面之后仍然是与原先全等的圆. 然后圆与圆之间通过曲面无缝连接,所以投影下来之后圆与圆之间通过公切线连接. 直接求有点难.把投影区域的上边界当成一个函数,然后套Simpson ...
- [NOI2005] 月下柠檬树 (自适应辛普森积分)
题目 原题链接:点这里 总体思路–>问题转化 先将原本的柠檬树分解成为多个圆台,再单独看圆台的投影 一个圆在地面的投影,是等比例的,而一条竖线的投影长度d=htanαd=\cfrac{h}{\ ...
- BZOJ 1502 月下柠檬树(simpson积分)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1502 题意:给出如下一棵分层的树,给出每层的高度和每个面的半径.光线是平行的,与地面夹角 ...
- [NOI2005]月下柠檬树(计算几何+积分)
题目描述 李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔 地照亮地面上的景物时,他必会悠闲地坐在他亲手植下的那棵柠檬树旁,独自思 索着人生的哲理. 李哲是一个喜爱思考的孩子,当他看 ...
- HYSBZ - 1502 月下柠檬树【辛普森积分】
李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔地照亮地面上的景物时,他必会悠闲地 坐在他亲手植下的那棵柠檬树旁,独自思索着人生的哲理.李哲是一个喜爱思考的孩子,当他看到在月光的照射 ...
- BZOJ 1502: [NOI2005]月下柠檬树 simpson积分
1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec Memory Limit: 64 MB Submit: 1244 Solved: 662 [Submit][Statu ...
- BZOJ 1502:月下柠檬树
BZOJ 1502:月下柠檬树 题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1502 题目大意:给出一棵由圆台构成的树以及一个平行光源,问 ...
- 【bzoj 1502】月下柠檬树
月下柠檬树 题意 求n个圆与他们的公切线的定积分. 解法 求出圆的公切线就可以了. 特别坑的一点 : 最两端的圆,有可能会被其他的圆所包含,所以要重新求一下最左端与最右端. 比较坑的一点 : 精度要设 ...
- [BZOJ1502]月下柠檬树(自适应辛普森积分)
1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec Memory Limit: 64 MB Submit: 1387 Solved: 739 [Submit][Statu ...
最新文章
- DPDK加速I/O虚拟化
- consul 命令行参数
- python中线条颜色_python中plot用法——线条、点、颜色
- 定时执行 Job - 每天5分钟玩转 Docker 容器技术(135)
- [js] pjax和ajax的区别是什么?
- 信息学奥赛C++语言:输出判断
- RBF的一维和二维逼近
- linux安装redis插件,Linux平台安装redis及redis扩展的方法
- Cocos2d-x 学习之引擎介绍
- adventnet trap
- web测试的基本流程
- 解决输入框中文英文长度限制不同的情况
- 一本通2056:【例3.7】最大的数
- 阿里云大学安全课程-阿里云首席安全研究员吴瀚清:WannaCry事件最“细思恐极“的一个事实是?...
- failed to open mysql_mysql解决fail to open file的方法
- 深度 | 巨头都在追逐的眼球追踪技术,究竟能带来什么?
- u盘删除文件怎么恢复,误删了u盘文件怎么恢复
- python分拣豆子_一, 认识一下Python
- 索尼大变身:消费电子业务转向医疗设备
- 故事得从西元1202年说起,话说有一位意大利青年,名叫斐波那契。 在他的一部著作中提出了一个有趣的问题:假设一对刚出生的小兔一个月后就能长成大兔, 再过一个月就能生下一对小兔,并且此后每个月都生一对小
热门文章
- android skype 无法用蓝牙耳机,Skype发布更新 增加蓝牙耳机稳定性
- mysql oltp_oltp数据库mysql
- http get post java_Java发送http的get、post请求 - 穿梭于偶然
- 【CSP201312-3】最大的矩形,单调栈
- ajax angular点击事件_Angular的$http的ajax的请求操作(推荐)
- 第七章节 类的抽象(接口)
- dfs-Bit Compression
- 保存最大的前20项暴力--Heritage of skywalkert
- 集训8.19最短路径讲解
- cshop是什么开发语言_C语言是用什么语言编写出来的?