Gym

题意:有A,B,C三个人要见面,每个人在[0,S]随机选择一个时间点作为见面时间,先到的那个人要等下一个人来了之后和他确认信息,然后马上就走。

例如,假如A先到,B其次,C最后到,那么A要等B到了之后和B确认完信息,然后A走,B再等C到了和C确认完信息,这样任务就完成了。

现给出A,B,C三人的最长等待时间wa,wb,wc,求任务能完成的概率。

题意等价于给出三条长度分别为wa,wb,wc且左端点在[0,S]内随机取值的线段,求第一条线段与第二条线段相交且第二条线段与第三条线段相交的概率。

假如A先到,B其次,C最后到,那么A的左端点取值范围在[0,S]间,B的左端点取值范围在[A,min(A+wa,S)]间,C的左端点取值范围在[B,min(B+wb,S)]间,因此A,B,C三点的取值空间对应的体积为$int_{0}^{S}dAint_{A}^{min(A+wa,S)}min(B+wb,S)dB$,这个积分直接求不大容易,可以用自适应simpson暴力搞一搞(注意要多分几段,确保不会出现观测错误)。由于A,B,C的先后排列顺序一共有6种情况,而且每种情况出现的概率相等,因此对每种情况分别求一下积分,然后除以S^3就是所求概率了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef double db;
 4 typedef db fun(db);
 5 const db eps=1e-10;
 6 const int N=20+10;
 7 db S,w[3],buf[3];
 8 int n,p[3];
 9 db simpson(db l,db r,fun f) {return (f(l)+f(r)+4*f((l+r)/2.0))*(r-l)/6.0;}
10 db rsimpson(db l,db r,fun f) {
11     db mid=(l+r)/2.0;
12     db a=simpson(l,r,f),b=simpson(l,mid,f),c=simpson(mid,r,f);
13     if(fabs(a-b-c)<eps)return b+c;
14     return rsimpson(l,mid,f)+rsimpson(mid,r,f);
15 }
16 db itg(db l,db r,fun f,int n=5) {
17     db ret=0,di=(r-l)/n;
18     for(db i=l; i<r-eps; i+=di)ret+=rsimpson(i,i+di,f);
19     return ret;
20 }
21 db fC(db x) {return 1.0;}
22 db fBC(db B0) {return min(B0+w[1],S)-B0;}
23 db fAB(db A0) {return rsimpson(A0,min(A0+w[0],S),fBC);}
24 db eq(db x,db y) {return fabs(x-y)<eps;}
25 db solve() {return itg(0,S,fAB);}
26 struct P {
27     db ans;
28     int i;
29     bool operator<(const P& b)const {return eq(ans,b.ans)?i<b.i:ans<b.ans;}
30 } q[N];
31 int main() {
32     scanf("%d",&n);
33     for(int i=0; i<n; ++i) {
34         scanf("%lf%lf%lf%lf",&S,&buf[0],&buf[1],&buf[2]);
35         db ans=0;
36         for(int i=0; i<3; ++i)p[i]=i;
37         do {
38             for(int i=0; i<3; ++i)w[i]=buf[p[i]];
39             ans+=solve();
40         } while(next_permutation(p,p+3));
41         ans/=S*S*S;
42         q[i]= {ans,i};
43     }
44     sort(q,q+n);
45     for(int i=0; i<n; ++i)printf("%d%c",q[i].i+1," 
"[i==n-1]);
46     return 0;
47 }

还有一种比较直观的做法,首先忽略C,画出A,B的分布空间,是一个二维平面上的梯形,如图所示:

接下来考虑C的取值,由于C的取值只与B有关,因此可以根据y轴上的位置来确定C的取值范围。可以发现,在B∈[0,S-wb]时,C的取值范围恒为[B,B+wb],长度恒为wb,而在B∈[S-wb,S]时,C的取值范围是成线性递减的。综上,可以把总的积分划分成V1和V2两个部分,其中V1=wa*wa*wb/2+(S-wa-wb)*wa*wb,V2=wa*wb*wb/2,化简即为(S-(wa+wb)/2)*wa*wb。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef double db;
 4 const int N=20+10;
 5 db S,w[3];
 6 int n;
 7 struct P {
 8     db ans;
 9     int i;
10     bool operator<(const P& b)const {return ans==b.ans?i<b.i:ans<b.ans;}
11 } q[N];
12 int main() {
13     scanf("%d",&n);
14     for(int i=0; i<n; ++i) {
15         scanf("%lf%lf%lf%lf",&S,&w[0],&w[1],&w[2]);
16         db ans=0;
17         for(int i=0; i<3; ++i)
18             for(int j=i+1; j<3; ++j)
19                 ans+=(S*2-w[i]-w[j])*w[i]*w[j];
20         ans/=S*S*S;
21         q[i]= {ans,i};
22     }
23     sort(q,q+n);
24     for(int i=0; i<n; ++i)printf("%d%c",q[i].i+1," 
"[i==n-1]);
25     return 0;
26 }
原文地址:https://www.cnblogs.com/asdfsag/p/11390459.html