BZOJ 1502:月下柠檬树

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1502

题目大意:给出一棵由圆台构成的树以及一个平行光源,问树的阴影面积.

扫描线+自适应Simpson积分

首先给出$Simpson$公式:$\int_l^rf(x)dx \approx \frac{r-l}{6}[f(l)+4f(\frac{r-l}{2})+f(r)]$

上述公式只能得出一个近似值,通常情况下与真实值相差甚远,故需要稍加改进为自适应$Simpson$积分:

  • 设$mid=\frac{r+l}{2}$,分别计算$L=Simpson(\int_l^{mid}f(x)dx)$,$R=Simpson(\int_{mid}^rf(x)dx)$,$S=Simpson(\int_l^rf(x)dx)$.
  • 若$L+R=S$,则可以认为$S=\int_l^rf(x)dx$;否则用$Simpson$公式递归计算函数在$[l,mid]$和$[mid,r]$的积分.

对于某些不易计算函数积分,能自动调整精度,但误差较大(精度在题目所要求的基础上多加几位),适用于较平滑的曲线;需要注意的是,自适应$Simpson$积分很容易被数据卡掉(毕竟我们只通过$5$个点来大致确定一个图像的面积),故求面积时最好分段。


由于题中给出的为平行光,故圆台底面投影在地面上的图形仍为圆。我们将整颗树切分成无数个截面,故树的投影即为无数个圆的投影的面积交,投影图像大致如下:

也就是说,阴影面积即为各个底面以及顶点的投影和两两圆的公切线所围成的面积。

设函数$F(t)$为扫描线$x=t$与上述图形所截的线段长度(显然$F(t)$是连续的),则阴影面积为$\int_L^RF(t)dt$,而这个积分可由$Simpson$公式轻松求得.

需要注意的是,若相邻两圆内含,则他们没有公切线。

代码如下:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #define Min(a,b) (a<b?a:b)
 5 #define Max(a,b) (a>b?a:b)
 6 #define N 505
 7 #define eps 1e-5
 8 using namespace std;
 9 const double inf=1e12;
10 int n,k;
11 double alpha,h0,h;
12 int dcmp(double x){
13     if(fabs(x)<eps)return 0;
14     else return x<0?-1:1;
15 }
16 struct point{
17     double x,y;
18     point(double X=0,double Y=0){x=X;y=Y;}
19 };
20 struct circle{
21     point p;
22     double r;
23     circle(point P=point(0,0),double R=0){p=P;r=R;}
24     bool within(circle t){
25         return dcmp(fabs(p.x-t.p.x)-fabs(r-t.r))<=0;
26     }
27 }c[N];
28 struct line{
29     point p,q;
30     double k,b;
31     line(point P=point(0,0),point Q=point(0,0)){
32         p=P;q=Q;
33         if(p.x>q.x)swap(p,q);
34         k=(p.y-q.y)/(p.x-q.x);
35         b=p.y-k*p.x;
36     }
37     double f(double x){
38         return k*x+b;
39     }
40 }l[N];
41 double F(double x){
42     double len=0;
43     for(int i=0;i<n;++i){//枚举圆与扫描线所截的最大长度
44         double d=fabs(c[i].p.x-x);
45         if(d-c[i].r<0)len=Max(len,2*sqrt(c[i].r*c[i].r-d*d));
46     }
47     for(int i=0;i<k;++i)//枚举公切线与扫描线所截的最大长度
48         if(l[i].p.x<x&&x<l[i].q.x)len=Max(len,fabs(l[i].f(x))*2);
49     return len;
50 }
51 double cal(double l,double r){
52     double mid=(l+r)/2;
53     return (F(l)+4*F(mid)+F(r))*(r-l)/6;
54 }
55 double simpson(double l,double r,double s){
56     double mid=(l+r)/2;
57     double x=cal(l,mid),y=cal(mid,r);
58     if(!dcmp(x+y-s))return s;
59     else return simpson(l,mid,x)+simpson(mid,r,y);
60 }
61 void solve(){
62     double L=inf,R=-inf;
63     for(int i=0;i<=n;++i){
64         L=Min(L,c[i].p.x-c[i].r);
65         R=Max(R,c[i].p.x+c[i].r);
66     }
67     for(int i=1;i<=n;++i){
68         if(c[i].within(c[i-1]))continue;//两圆内含的情况
69         double sin_theta=(c[i].r-c[i-1].r)/(c[i].p.x-c[i-1].p.x);
70         double cos_theta=sqrt(1-sin_theta*sin_theta);
71         l[k++]=line(point(c[i].p.x-c[i].r*sin_theta,c[i].r*cos_theta),
72                     point(c[i-1].p.x-c[i-1].r*sin_theta,c[i-1].r*cos_theta));
73     }
74     printf("%.2lf\n",simpson(L,R,cal(L,R)));
75 }
76 int main(void){
77     scanf("%d%lf%lf",&n,&alpha,&h0);
78     for(int i=0;i<n;++i){
79         c[i].p=point(h0/tan(alpha),0);
80         scanf("%lf",&h);
81         h0+=h;
82     }
83     c[n].p=point(h0/tan(alpha),0);c[n].r=0;
84     for(int i=0;i<n;++i)scanf("%lf",&c[i].r);
85     solve();
86 }

去掉部分判断语句后,从原来的TLE(6000ms)变成了372ms,不是很懂为什么差距这么大。

转载于:https://www.cnblogs.com/barrier/p/6512826.html

BZOJ 1502:月下柠檬树相关推荐

  1. BZOJ 1502 月下柠檬树(simpson积分)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1502 题意:给出如下一棵分层的树,给出每层的高度和每个面的半径.光线是平行的,与地面夹角 ...

  2. bzoj 1502月下柠檬树 Simpson积分

    关键点是,水平的圆投影到水平面之后仍然是与原先全等的圆. 然后圆与圆之间通过曲面无缝连接,所以投影下来之后圆与圆之间通过公切线连接. 直接求有点难.把投影区域的上边界当成一个函数,然后套Simpson ...

  3. HYSBZ - 1502 月下柠檬树【辛普森积分】

    李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔地照亮地面上的景物时,他必会悠闲地 坐在他亲手植下的那棵柠檬树旁,独自思索着人生的哲理.李哲是一个喜爱思考的孩子,当他看到在月光的照射 ...

  4. BZOJ 1502: [NOI2005]月下柠檬树 simpson积分

    1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1244  Solved: 662 [Submit][Statu ...

  5. 【bzoj 1502】月下柠檬树

    月下柠檬树 题意 求n个圆与他们的公切线的定积分. 解法 求出圆的公切线就可以了. 特别坑的一点 : 最两端的圆,有可能会被其他的圆所包含,所以要重新求一下最左端与最右端. 比较坑的一点 : 精度要设 ...

  6. 1502: [NOI2005]月下柠檬树

    1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1077  Solved: 600 [Submit][Statu ...

  7. [BZOJ1502]月下柠檬树(自适应辛普森积分)

    1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1387  Solved: 739 [Submit][Statu ...

  8. 【BZOJ-1502】月下柠檬树 计算几何 + 自适应Simpson积分

    1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1017  Solved: 562 [Submit][Statu ...

  9. 【NOI2005】 月下柠檬树

    题目描述 月下柠檬树 主文件名:lemon [问题描述] 李哲非常非常喜欢柠檬树, 特别是在静静的夜晚,当天空中有一弯明月温柔 地照亮地面上的景物时, 他必会悠闲地坐在他亲手植下的那棵柠檬树旁,独自思 ...

最新文章

  1. 操作系统学习:Linux0.12文件异步IO
  2. HDU4920(矩阵连乘)
  3. 如何用python创建一个下载网站-使用Python下载文件的简单示例
  4. TPS(薄板样条) 2D 插值
  5. 响应式html5模板代码,响应式多用途HTML5模板
  6. 计蒜客挑战难题:爬楼梯
  7. JavaScript常用设计模式
  8. mysql启动成功但是没有进程_zabbix_server表面启动成功,但是没有进程
  9. maven配置eclipse案例及命令
  10. UDP协议和TCP协议
  11. 微信支付 (APP端开发)
  12. ViewStub用法
  13. 均匀权重向量集合的生成
  14. 什么是SLA?SLA服务水平深度解析
  15. 【沧海拾昧】微机原理:并行接口电路8255芯片
  16. SQL Transformation
  17. Java快速开发框架_若依——Ruoyi-SpringCloud版本-2.安装redis服务端和客户端-win7
  18. MFC从字体名获取字库文件路径(从宋体获取到simsun.ttc)
  19. 移动页面input手机键盘中的“搜索”按键
  20. 申请支付宝授权,提现测试环境步骤

热门文章

  1. mysql 存储过程复杂查询_SQL分页存储过程 支持连接查询等复杂的SQL
  2. 自主云服务器处理器_云服务器对处理器的要求
  3. oracle上浮下浮分析函数_Oracle分析函数简析
  4. 小学计算机课的评语,小学信息技术评课稿
  5. html 自动完成,如何指定 form或 input元素是否应在HTML中启用自动完成功能?
  6. html中在哪儿使用div,使用javascript在html中使用div
  7. html 复选按钮(input checkbox)
  8. go语言 gosched
  9. ubuntu 网络配置
  10. 2020年已裸辞5个月(软文)