A Dangerous Maze (II) LightOJ - 1395
这个题是 LightOJ 1027 A Dangerous Maze 基础概率DP 的加强版。
有 n 个门,其中有些门通过之后, xi 分钟后会回到原点,另一些门通过后,xi 分钟后会出去,现在能够记住最近的 K 次选择,下次选择时会从剩下的未在这 K 次选择中出现的门进行选择,问出去的期望时间。
首先这 K 次记住的肯定是未出去的门,因为假如出去的话就已经结束了,不需要再进行选择,定义出去的门为集合 A,返回的门为集合 B,用 dp[i] 表示记忆了 i 个未出去的门对应的期望,分两种情况进行讨论:
(1)假如 K≥∣B∣,也就是说记忆的 K 个经验能够包括到所有回来的门,则 dp[∣B∣]=∣A∣1i∈A∑xi,即此时的期望就等于从能够出去的门中选一个之后的期望时间。此时再推 j<∣B∣ 时对应的 dp 值,此时 dp[j]=n−j1i∈A∑xi+n−j1(i∈B∖C∑(xi+dp[j+1])),其中 C 表示已经选择过的 j 个不能出去的门的集合,B∖C 表示还未选择的不能出去的门的集合,因为 C 是一个随机选择出来的集合,可以证明:
i∈B∖C∑xi=∣B∣∣B∖C∣i∈B∑xi
因此:
dp[j]dp[j]=n−j1i∈A∑xi+n−j∣B∖C∣(∣B∣∑i∈Bxi+dp[j+1])=n−j1i∈A∑xi+n−j∣B∣−j(∣B∣∑i∈Bxi+dp[j+1])
逆推即可以求得 dp[0]。
(2)假如 K<∣B∣,也就是说并不能完全记住所有的返回门,那么 j=K 时:
dp[K]dp[K]=n−K1i∈A∑xi+n−K∣B∣−K(∣B∣∑i∈Bxi+dp[K])=n−∣B∣1i∈A∑xi+n−∣B∣∣B∣−K∣B∣∑i∈Bxi
j<K 时:
dp[j]=n−j1i∈A∑xi+n−j∣B∣−j(∣B∣∑i∈Bxi+dp[j+1])
也可以逆推求得 dp[0]。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int T,iCase,n,K,a,ca,cb,sa,sb;
double res;
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&K);
ca=cb=sa=sb=0;
for(int i=0;i<n;i++){
scanf("%d",&a);
if(a>0)ca++,sa+=a;
else cb++,sb+=-a;
}
if(cb==n){
printf("Case %d: -1\n",++iCase);
continue;
}
K=min(K,cb);
if(K<cb)res=1.0/(n-cb)*sa+1.0*(cb-K)*sb/(n-cb)/cb;
else res=1.0*sa/ca;
for(int j=K-1;j>=0;j--)
res=1.0*sa/(n-j)+1.0*(cb-j)/(n-j)*(1.0*sb/cb+res);
printf("Case %d: %.8lf\n",++iCase,res);
}
return 0;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200326222127687.png)