【NOI2004】 降雨量

题目描述
降雨量

【问题描述】
M国是个多雨的国家,尤其是P城,频繁的降雨给人们的出行带来了不少麻烦。为了方便行人雨天过马路,有关部门在每处人行横道的上空都安装了一种名为“自动伞”的装置。(如图1所示)

图1
每把自动伞都可以近似地看作一块长方形的板,厚度不计。这种伞有相当出色的吸水能力,落到上面的雨水都会完全被伞顶的小孔吸入,并通过管道运走。不下雨时,这些伞闲置着。一旦下雨,它们便立刻开始作匀速率直线往返运动:从马路的一边以固定的速率移动到另一边,再从另一边以相同的速率返回,如此往复,直到雨停为止。任何时刻自动伞都不会越过马路的边界。有了自动伞,下雨天没带伞的行人只要躲在伞下行走,就不会被雨淋着了。
由于自动伞的大小有限,当需要使用自动伞过马路的人比较多时,一把自动伞显然是不够的,所以有关部门在几处主要的人行横道上空安装了多把自动伞。每把自动伞的宽度都等于人行横道的宽度,高度各不相同,长度不一定相同,移动速率也不一定相同。
现在已知一处人行横道的详细情况,请你计算从开始下雨到T秒钟后的这段时间内,一共有多少体积的雨水降落到人行横道上。

【输入文件】
第一行有四个整数N,W,T,V。N表示自动伞的数目,W表示马路的宽度,T表示需要统计从开始下雨到多长时间后的降雨情况,V表示单位面积单位时间内的降雨体积。
为了描述方便,我们画出了一个如图2所示的天空中五把伞的剖面图,取马路左边界为原点,取向右为x轴正方向,取向上为y轴正方向,建立平面直角坐标系。这样,每把自动伞都可以看作平面上的一条线段。

图2
接下来的N行,每行用三个整数描述一把自动伞。第一个数x是伞的初始位置,用它左端点的横坐标表示。第二个数l是伞的长度,即x方向上的尺寸。第三个数v是伞的速度,v的大小表示移动的速率。如果v>0,表示开始时伞向右移动;如果v<0,表示开始时伞向左移动;如果v=0,表示伞不动。

【输出文件】
输出文件只包含一个实数,表示从开始下雨到T秒钟后,一共有多少体积的水降落到人行横道上。输出结果精确到小数点后第二位。

【约定】
雨点均匀地匀速竖直下落
自动伞和马路两者都是水平的
自动伞的宽度和人行横道的宽度相等,都等于1


所有自动伞的往返次数之和不超过250,一来一回算一个往返。

【样例输入】
2 4 3 10
0 1 1
3 1 -1

【样例输出】
65.00

 

题解

 

解法1:simpson自适应公式
 1 /*
 2     *Problem:    NOI2004 降雨量
 3     *Author :    Chen Yang
 4     *Time   :    2012.6.11 4:00 pm
 5     *State  :    90分
 6     *Memo   :    计算几何之simpson
 7 */
 8 #include <cstdio>
 9 #include <cstdlib>
10 #include <cmath>
11 #include <cstring>
12 #include <string>
13 #include <algorithm>
14 using namespace std;
15 typedef double DB;
16 const int maxn=301, inf = 100000000;
17 const DB zero = 1e-8;
18 int n, m, w, T, V;
19 struct line {DB x,y,len,k,L,R;} L[5010];
20 struct inter {DB l,r;} c[maxn];
21 
22 bool cmp(const inter &a, const inter &b) 
23 {return a.l<b.l || (a.l == b.l && a.r < b.r);}
24 
25 DB f(DB x)
26 {
27     DB s = 0; int p = 0;
28     for (int i=1; i<=m; ++i)
29     if (L[i].L<x && x<L[i].R)
30     {
31         if (fabs(L[i].k)>zero)
32         {
33             DB t1=(x-L[i].x)*L[i].k+L[i].y;
34             DB t2=(x-L[i].x-L[i].len)*L[i].k+L[i].y;
35             c[++p].l = max(L[i].y,min(t1,t2)); 
36             c[p].r = min(L[i].y+fabs(L[i].k*(L[i].R-L[i].L-L[i].len)),max(t1,t2));
37         } else return T;
38     }
39     if (!p) return 0;
40     sort(c+1, c+p+1, cmp);
41     DB l = c[1].l, r = c[1].r;
42     for (int i=2; i<=p; ++i)
43     if (c[i].l>r) s += r-l, l = c[i].l, r = c[i].r;
44     else r = max(c[i].r,r);
45     s += r-l;
46     return s;
47 }
48 
49 inline DB simpson(DB a, DB b, DB fa, DB fm, DB fb)
50 { return (b-a)/6*(fa+4*fm+fb); }
51 
52 DB calc(DB l, DB fl, DB m, DB fm, DB r, DB fr, DB pre)
53 {
54     DB ls=(l+m)/2, rs=(m+r)/2, fls=f(ls), frs=f(rs);
55     DB la=simpson(l,m,fl,fls,fm), ra=simpson(m,r,fm,frs,fr);
56     return fabs(la+ra-pre)<zero? pre:calc(l,fl,ls,fls,m,fm,la)+calc(m,fm,rs,frs,r,fr,ra);
57 }
58 
59 inline DB area(DB l, DB r)
60 {
61     DB m=(l+r)/2, fl=f(l), fr=f(r), fm=f(m);
62     DB pre = simpson(l,r,fl,fm,fr);
63     return calc(l,fl,m,fm,r,fr,pre);
64 }
65 
66 void check(DB x, DB y, DB len, DB v, DB t)
67 {
68     DB l = min(x,x+t*v), r = max(x+len,x+len+t*v);
69     L[++m].L = l, L[m].R = r, L[m].k = 1/v;
70     L[m].x = x, L[m].y = y, L[m].len = len;
71     if (r>w)
72     {
73         L[m].R = w; 
74         check(w-len, y+(w-len-x)/v, len, -v, t-(w-len-x)/v);
75     } else
76     if (l<-zero)
77     {
78         L[m].L = 0;
79         check(0, y-x/v, len, -v, t+x/v);
80     }
81 }
82 
83 int main()
84 {
85     freopen("rainfall.in", "r", stdin);
86     freopen("rainfall.out", "w", stdout);
87     scanf("%d%d%d%d", &n, &w, &T, &V);
88     for (int i=1; i<=n; ++i)
89     {
90         DB x, l, v;
91         scanf("%lf%lf%lf", &x, &l, &v);
92         if (fabs(v)>zero && (x!=0 || l!=w)) check(x,0,l,v,(DB) T);
93         else L[++m].k = 0, L[m].L = x, L[m].R = x+l;
94     }
95     printf("%.2lf\n", (T*w-area(0,w))*V);
96     return 0;
97 }

 

解法2:分段求面积
  1 /*
  2     *Problem:    NOI2004 降雨量
  3     *Author :    Chen Yang
  4     *Time   :    2012.6.11 4:00 pm
  5     *State  :    AC
  6     *Memo   :    计算几何之平行四边形面积并
  7 */
  8 #include <cstdio>
  9 #include <cstdlib>
 10 #include <cmath>
 11 #include <cstring>
 12 #include <string>
 13 #include <algorithm>
 14 using namespace std;
 15 typedef double DB;
 16 const int maxn=301, maxm=5010, inf = 100000000;
 17 const DB zero = 1e-8;
 18 int n, m, w, T, V, fs;
 19 DB a[maxm];
 20 struct line {DB x,y,len,k,L,R;} L[maxm];
 21 struct inter {DB l,r;} c[maxn];
 22 
 23 bool cmp(const inter &a, const inter &b) 
 24 {return a.l<b.l || (a.l == b.l && a.r < b.r);}
 25 
 26 DB f(DB x)
 27 {
 28     DB s = 0; int p = 0;
 29     for (int i=1; i<=m; ++i)
 30     if (L[i].L<=x && x<=L[i].R)
 31     {
 32         c[++p].l = (x-L[i].x)*L[i].k+L[i].y; 
 33         c[p].r = c[p].l+L[i].len;
 34     }
 35     if (!p) return 0;
 36     sort(c+1, c+p+1, cmp);
 37     DB l = c[1].l, r = c[1].r;
 38     for (int i=2; i<=p; ++i)
 39     if (c[i].l>r) s += r-l, l = c[i].l, r = c[i].r;
 40     else r = max(c[i].r,r);
 41     s += r-l;
 42     return s;
 43 }
 44 
 45 inline DB area()
 46 {
 47     DB s = 0;
 48     for (int i=2; i<=fs; ++i)
 49         s += (f(a[i])+f(a[i-1]))*(a[i]-a[i-1])/2;
 50     return s;
 51 }
 52 
 53 void check(DB x, DB y, DB len, DB v, DB t)
 54 {
 55     L[++m].L = x, L[m].R = x+t, L[m].k = v;
 56     L[m].x = x, L[m].y = y, L[m].len = len;
 57     DB l = y+t*v, r = y+len+t*v;
 58     if (r>w+zero)
 59     {
 60         L[m].R = x+(w-len-y)/v; 
 61         check(L[m].R, w-len, len, -v, t-(w-len-y)/v);
 62     } else
 63     if (l<-zero)
 64     {
 65         L[m].R = x-y/v;
 66         check(L[m].R, 0, len, -v, t+y/v);
 67     } else a[++fs] = x+t;
 68     a[++fs] = x;
 69 }
 70 
 71 inline bool cross(int i, int j)
 72 {
 73     return L[i].R>=L[j].L && L[i].L<=L[j].R && fabs(L[i].k-L[j].k)>zero;
 74 }
 75 
 76 void get_p(int i, int j)
 77 {
 78     DB x1 = L[i].x, x2 = L[j].x, y1 = L[i].y, y2 = L[j].y;
 79     DB k1 = L[i].k, k2 = L[j].k, L1 = L[i].L, L2 = L[j].L;
 80     DB R1 = L[i].R, R2 = L[j].R, len1 = L[i].len, len2 = L[j].len;
 81     DB x = (y2-y1+x1*k1-x2*k2)/(k1-k2);
 82     if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x;
 83     x = (y2+len2-y1+x1*k1-x2*k2)/(k1-k2);
 84     if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x;
 85     x = (y2-len1-y1+x1*k1-x2*k2)/(k1-k2);
 86     if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x;
 87     x = (y2+len2-len1-y1+x1*k1-x2*k2)/(k1-k2);
 88     if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x;
 89 }
 90 
 91 int main()
 92 {
 93     freopen("rainfall.in", "r", stdin);
 94     freopen("rainfall.out", "w", stdout);
 95     scanf("%d%d%d%d", &n, &w, &T, &V);
 96     for (int i=1; i<=n; ++i)
 97     {
 98         DB x, l, v;
 99         scanf("%lf%lf%lf", &x, &l, &v);
100         if (x || l!=w) check(0,x,l,v,(DB) T);
101         else {printf("0.00"); return 0;};
102     }
103     for (int i=1; i<=m; ++i)
104     for (int j=1; j<=m; ++j)
105         if (i!=j && cross(i,j)) get_p(i,j);
106     sort(a+1, a+fs+1);
107     printf("%.2lf\n", (T*w-area())*V);
108     return 0;
109 }

 

posted @ 2012-06-12 18:05  datam  阅读(856)  评论(1编辑  收藏  举报