A Dangerous Maze (II) LightOJ - 1395
这个题是 LightOJ 1027 A Dangerous Maze 基础概率DP 的加强版。
有 n n n 个门,其中有些门通过之后, x i x_i xi 分钟后会回到原点,另一些门通过后, x i x_i xi 分钟后会出去,现在能够记住最近的 K K K 次选择,下次选择时会从剩下的未在这 K K K 次选择中出现的门进行选择,问出去的期望时间。
首先这 K K K 次记住的肯定是未出去的门,因为假如出去的话就已经结束了,不需要再进行选择,定义出去的门为集合 A \mathcal{A} A,返回的门为集合 B \mathcal{B} B,用 d p [ i ] dp[i] dp[i] 表示记忆了 i i i 个未出去的门对应的期望,分两种情况进行讨论:
(1)假如 K ≥ ∣ B ∣ K\ge|\mathcal{B}| K≥∣B∣,也就是说记忆的 K K K 个经验能够包括到所有回来的门,则 d p [ ∣ B ∣ ] = 1 ∣ A ∣ ∑ i ∈ A x i dp[|\mathcal{B}|]=\dfrac{1}{|\mathcal{A}|}\sum\limits_{i\in\mathcal{A}}x_i dp[∣B∣]=∣A∣1i∈A∑xi,即此时的期望就等于从能够出去的门中选一个之后的期望时间。此时再推 j < ∣ B ∣ j<|\mathcal{B}| j<∣B∣ 时对应的 d p dp dp 值,此时 d p [ j ] = 1 n − j ∑ i ∈ A x i + 1 n − j ( ∑ i ∈ B ∖ C ( x i + d p [ j + 1 ] ) ) dp[j]=\dfrac{1}{n-j}\sum\limits_{i\in\mathcal{A}}x_i+\dfrac{1}{n-j}(\sum\limits_{i\in\mathcal{B}\setminus\mathcal{C}}(x_i+dp[j+1])) dp[j]=n−j1i∈A∑xi+n−j1(i∈B∖C∑(xi+dp[j+1])),其中 C \mathcal{C} C 表示已经选择过的 j j j 个不能出去的门的集合, B ∖ C \mathcal{B}\setminus\mathcal{C} B∖C 表示还未选择的不能出去的门的集合,因为 C \mathcal{C} C 是一个随机选择出来的集合,可以证明:
∑ i ∈ B ∖ C x i = ∣ B ∖ C ∣ ∣ B ∣ ∑ i ∈ B x i \sum_{i\in\mathcal{B}\setminus\mathcal{C}}x_i=\frac{|\mathcal{B}\setminus\mathcal{C}|}{|\mathcal{B}|}\sum_{i\in\mathcal{B}}x_i i∈B∖C∑xi=∣B∣∣B∖C∣i∈B∑xi
因此:
d
p
[
j
]
=
1
n
−
j
∑
i
∈
A
x
i
+
∣
B
∖
C
∣
n
−
j
(
∑
i
∈
B
x
i
∣
B
∣
+
d
p
[
j
+
1
]
)
d
p
[
j
]
=
1
n
−
j
∑
i
∈
A
x
i
+
∣
B
∣
−
j
n
−
j
(
∑
i
∈
B
x
i
∣
B
∣
+
d
p
[
j
+
1
]
)
\begin{aligned} dp[j]&=\frac{1}{n-j}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}\setminus\mathcal{C}|}{n-j}(\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}+dp[j+1])\\ dp[j]&=\frac{1}{n-j}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}|-j}{n-j}(\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}+dp[j+1])\\ \end{aligned}
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])
逆推即可以求得
d
p
[
0
]
dp[0]
dp[0]。
(2)假如 K < ∣ B ∣ K<|\mathcal{B}| K<∣B∣,也就是说并不能完全记住所有的返回门,那么 j = K j=K j=K 时:
d p [ K ] = 1 n − K ∑ i ∈ A x i + ∣ B ∣ − K n − K ( ∑ i ∈ B x i ∣ B ∣ + d p [ K ] ) d p [ K ] = 1 n − ∣ B ∣ ∑ i ∈ A x i + ∣ B ∣ − K n − ∣ B ∣ ∑ i ∈ B x i ∣ B ∣ \begin{aligned} dp[K]&=\frac{1}{n-K}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}|-K}{n-K}(\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}+dp[K])\\ dp[K]&=\frac{1}{n-|\mathcal{B}|}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}|-K}{n-|\mathcal{B}|}\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}\\ \end{aligned} 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 j<K j<K 时:
d p [ j ] = 1 n − j ∑ i ∈ A x i + ∣ B ∣ − j n − j ( ∑ i ∈ B x i ∣ B ∣ + d p [ j + 1 ] ) dp[j]=\frac{1}{n-j}\sum_{i\in\mathcal{A}}x_i+\frac{|\mathcal{B}|-j}{n-j}(\frac{\sum_{i\in\mathcal{B}}x_i}{|\mathcal{B}|}+dp[j+1]) dp[j]=n−j1i∈A∑xi+n−j∣B∣−j(∣B∣∑i∈Bxi+dp[j+1])
也可以逆推求得 d p [ 0 ] dp[0] dp[0]。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
//#define WINE
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;
}