题意:一开始给你一个得到箱子的概率q = 2%,还有一个每局游戏获胜的概率p(输入)。然后按照以下的规则进行游戏:
1.游戏开始,如果玩家赢了走到第2步,否则走到第3步
2.玩家有q的概率得到一个箱子,玩家得到箱子后游戏就会立即结束,如果没有得到箱子,那么q += 2%
3.q += 1.5%
4.回到1,重复上述步骤直到游戏结束。
问你玩家玩到游戏结束,进行局数的期望是多少局?
思路:好像是套路的概率dp题求期望,dp[q]代表当前概率为q时进行游戏局数的期望。我们知道到q的概率达到100%的时候,我们只要赢了游戏那么就一定会结束游戏,也就是说p为100%时,进行局数的期望符合伯努利试验的几何分布的情况(即n次游戏前n-1次都是数的,第n次赢了),套用公式即为 E = 1/p,所以这样我们就可以确定dp[100]的期望了。然后我们逆推公式即可得到dp[2]的期望,也就是题目给出的我们的期望。
这里对于逆推的理解,我觉得可能是因为后面的概率也就是100%概率下,期望值比较好直接确定。
对于概率dp,kaungbin这样说,概率DP主要用于求解期望,概率等题目。转移方程比较灵活。一般求概率正推,求期望是逆推。
一般的DP,dp[x]代表到当前这一下状态x下有多少,而期望dp[x]可以表示为在当前状态x下还差多少到达最终状态。
这道题转移方程dp[i] = p*(1-q)*dp[min(q+2,100)] + (1-p)*dp[min(q+1.5,100)] + 1。1代表当前这一游戏局数,p * (1-q)*dp[min(q+2,100)] 代表有p * (1-q)的概率加上dp[min(q+2,100)] 的局数到达最终的状态,另外一个同理。
ps:因为用数组保存概率不能有小数,所以扩大成整数就可以了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int eps = 1e-6;
const int MAXN = 1e3+7;
double dp[MAXN];
//这里用数组存一下概率 所以1.5 把它扩大成整数去存
int main()
{
int T,cas = 0;
scanf("%d",&T);
while(T--){
double p;
memset(dp,0,sizeof(dp));
scanf("%lf",&p);
p /= 100;
dp[1000] = 1/p;//伯努利实验 几何分布的公式
//cout<<p<<' '<<dp[1000]<<endl;
for(int i = 999;i >= 20;i --){//dp[20]也就是初始的q = 2%使我们到达的最终状态
dp[i] = p*(1.0-(1.0*i)/1000)*dp[min(i+20,1000)] + (1.0-p)*dp[min(i+15,1000)] + 1.0;//1代表我当前的这一局
}
printf("Case %d: %.10f\n",++cas,dp[20]);
}
return 0;
}