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 }

 

posted @ 2017-03-09 01:11  barriery  阅读(183)  评论(0编辑  收藏  举报