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; }