题意:给出n扇门,每扇门都给出一个数x,若为正数,则表示在x时间后走出迷宫,若为负数,则表示在x时间后回到起点,你会记得最后k扇你走过的门(不会再走),求最后的期望时间。
题解:概率dp
这题的进阶版,原版不会记住走了哪扇门。一样的思路。
用
d
p
[
i
]
dp[i]
dp[i]表示记住
i
i
i扇门之后走出去还需要的期望时间。
n1:正数数量 n2:负数数量
s1:正数之和 s2:负数之和
①当k>=n2时,dp[k] = s1 / n1
,相当于走任意一扇均可。
②当k<n2时,dp[k] = s1 / (n - k) + (n2 - k) * (dp[k] + s2 / n2) / (n - k)
,即走出去的期望时间+走回来再走出去的期望时间。化简得
d
p
[
k
]
dp[k]
dp[k]即可。因为不确定走的哪扇负数的门,既然求期望,直接对于单扇门取平均值即可。
确定了终值,往前递推。
方程为:dp[i] = s1 / (n - i) + (n2 - i) * (dp[i + 1] + s2 / n2) / (n - i)
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
int t, n, k, a[111];
double dp[111];
int main() {
int cas = 0;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &k);
double s1 = 0, s2 = 0, n1 = 0, n2 = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i] > 0) n1++, s1 += a[i];
else n2++, s2 += -a[i];
}
if (n2 == n) {
printf("Case %d: -1\n", ++cas);
continue;
}
if (k >= n2) dp[k = n2] = s1 / n1;
else dp[k] = (s1 / (n - k) + (n2 - k) * (s2 / n2) / (n - k)) / (1 - (n2 - k) / (n - k));
for (int i = k - 1; i >= 0; i--) {
dp[i] = s1 / (n - i) + (n2 - i) * (dp[i + 1] + s2 / n2) * 1.0 / (n - i);
}
printf("Case %d: %f\n", ++cas, dp[0]);
}
return 0;
}