ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

Input

文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度)。第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的高度和每层的高度。第3行包含n个实数r1,r2,…,rn,表示柠檬树每层下底面的圆的半径。上述输入文件中的数据,同一行相邻的两个数之间用一个空格分隔。输入的所有实数的小数点后可能包含1至10位有效数字。

Output

输出1个实数,表示树影的面积。四舍五入保留两位小数。

圆台被平行光投影到平面上得到的是圆和梯形的并,方便起见可以用simpson积分近似求面积

#include<cstdio>
#include<cmath>
#include<map>
typedef long double ld;
int n,p=0;
ld a;
ld h[512],r[512];
ld xa[512],xb[512],ya[512],yb[512];
std::map<ld,ld>mp;
ld H(ld x){
    std::map<ld,ld>::iterator it=mp.find(x);
    if(it!=mp.end())return it->second;
    ld y=0;
    for(int i=0;i<n;i++)if(fabs(h[i]-x)<r[i]){
        ld t=sqrt(r[i]*r[i]-(h[i]-x)*(h[i]-x));
        if(t>y)y=t;
    }
    for(int i=0;i<p;i++)if(xa[i]<=x&&x<=xb[i]){
        ld t=(x-xa[i])/(xb[i]-xa[i])*(yb[i]-ya[i])+ya[i];
        if(t>y)y=t;
    }
    return mp[x]=y;
}
ld S(ld l,ld r){
    ld m=(l+r)/2.,m1=(l+m)/2.,m2=(m+r)/2.;
    ld a=(H(l)+H(r)+H(m)*4)*(r-l)/3.;
    ld b=(H(l)+H(r)+H(m)*2+H(m1)*4+H(m2)*4)*(r-l)/6.;
    if(fabs(a-b)<1e-6)return b;
    return S(l,m)+S(m,r);
}
int main(){
    scanf("%d%llf%llf",&n,&a,h);
    h[0]=0;
    for(int i=1;i<=n;i++)scanf("%llf",h+i);
    for(int i=1;i<=n;i++)h[i]+=h[i-1];
    for(int i=1;i<=n;i++)h[i]=fabs(h[i]/tan(a));
    for(int i=0;i<n;i++)scanf("%llf",r+i);
    r[n]=0;
    ld mx=h[n],mn=h[0]-r[0];
    for(int i=0;i<n;i++){
        if(h[i]+r[i]>mx)mx=h[i]+r[i];
        if(h[i]-r[i]<mn)mn=h[i]-r[i];
        if(h[i]+r[i]>=h[i+1]+r[i+1]||h[i]-r[i]>=h[i+1]-r[i+1])continue;
        ld c=(r[i]-r[i+1])/(h[i+1]-h[i]);
        ld s=sqrt(1-c*c);
        xa[p]=h[i]+c*r[i];
        xb[p]=h[i+1]+c*r[i+1];
        ya[p]=s*r[i];
        yb[p]=s*r[i+1];
        p++;
    }
    printf("%.2lf\n",(double)S(mn,mx));
    return 0;
}

 

posted on 2016-06-28 08:59  nul  阅读(299)  评论(0编辑  收藏  举报