Shadow of Survival
Shadow of Survival
题目链接:http://dutacm.club:7217/codesheaven/problem.php?id=1083
题目大意:给出一个由圆台构成的塔和一个点光源,问塔的阴影面积.
Simpson积分
注意到圆台底面由点光源投影后仍为圆(对应弦成正比),于是就与这道题类似http://www.cnblogs.com/barrier/p/6512826.html.不再赘述,经测试eps取1e-5时最优.
/*需要注意的是,#define Abs(x) (x>0?x:-x) 这种写法可能会因为x为复合表达式而导致运算错误*/
代码如下:
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #define N 1005 5 using namespace std; 6 const double eps=1e-5; 7 const double inf=1e12; 8 double d,z; 9 int n,k; 10 int dcmp(double x){ 11 if(fabs(x)<eps)return 0; 12 else return x<0?-1:1; 13 }; 14 struct point{ 15 double x,y; 16 point(double X=0,double Y=0){x=X;y=Y;} 17 }; 18 struct circle{ 19 point o; 20 double r; 21 circle(point O=point(0,0),double R=0){o=O;r=R;} 22 bool within(circle tmp){ 23 return fabs(o.x-tmp.o.x)-fabs(r-tmp.r)<=0; 24 } 25 bool xin(double x){ 26 return o.x-r<=x&&x<=o.x+r; 27 } 28 }c[N]; 29 struct line{ 30 point s,t; 31 double k,b; 32 line(point S=point(-1,0),point T=point(1,0)){ 33 s=S;t=T; 34 if(s.x>t.x)swap(s,t); 35 k=(s.y-t.y)/(s.x-t.x); 36 b=s.y-k*s.x; 37 } 38 bool xin(double x){ 39 return s.x<=x&&x<=t.x; 40 } 41 double f(double x){ 42 return k*x+b; 43 } 44 }l[N]; 45 void init(){ 46 scanf("%lf",&c[0].r); 47 c[0].o=point(0,0); 48 k=0; 49 for(int i=1;i<n;++i){ 50 double h,r; 51 scanf("%lf%lf",&h,&r); 52 c[i]=circle(point(h*d/(z-h),0),z*r/(z-h)); 53 } 54 for(int i=1;i<n;++i){ 55 if(c[i].within(c[i-1]))continue; 56 double sin_theta=(c[i].r-c[i-1].r)/(c[i].o.x-c[i-1].o.x); 57 double cos_theta=sqrt(1-sin_theta*sin_theta); 58 l[k++]=line(point(c[i-1].o.x-c[i-1].r*sin_theta,c[i-1].r*cos_theta), 59 point(c[i].o.x-c[i].r*sin_theta,c[i].r*cos_theta)); 60 } 61 } 62 double F(double x){ 63 double len=0; 64 for(int i=0;i<n;++i){ 65 if(c[i].xin(x)){ 66 double d=c[i].o.x-x; 67 len=max(len,2*sqrt(c[i].r*c[i].r-d*d)); 68 } 69 } 70 for(int i=0;i<k;++i) 71 if(l[i].xin(x)) 72 len=max(len,2*l[i].f(x)); 73 return len; 74 } 75 double cal(double l,double r){ 76 return (F(l)+4*F((l+r)/2)+F(r))/6*(r-l); 77 } 78 double simpson(double l,double r,double s){ 79 double mid=(l+r)/2; 80 double x=cal(l,mid),y=cal(mid,r); 81 if(!dcmp(x+y-s))return s; 82 else return simpson(l,mid,x)+simpson(mid,r,y); 83 } 84 void solve(){ 85 double L=inf,R=-inf; 86 for(int i=0;i<n;++i){ 87 L=min(L,c[i].o.x-c[i].r); 88 R=max(R,c[i].o.x+c[i].r); 89 } 90 printf("%.2lf\n",simpson(L,R,cal(L,R))); 91 } 92 int main(void){ 93 while(~scanf("%lf%lf%d",&d,&z,&n)){ 94 init(); 95 solve(); 96 } 97 }