概率期望dp一般都是逆推。正推的话要计算期望的期望,非常麻烦!一般来说,总有一个末状态是一定会发生,从这个状态开始逆推可以简化许多问题。
期望dp和普通的dp的不同处。普通的dp可能纪录的是dp[i]到了i这个状态时的最优解,而期望dp一般纪录dp[i]以i这个状态为起点能得到的最优解。
E.Discovering Gold
题意:大富翁地图。丢筛子,每个格子有val,如果最后丢出筛子超出终点就重新丢,求最后获得的val期望。
解题思路:不难发现,最后会一定停在终点。所以建立dp[终点]=1*val[终点],向前推。dp储存从这个点开始能获得的总价值的期望
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=10007;
const int maxn=1E5+5;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
int num[105];
double dp[105];
int main (){
int t,n;
scanf ("%d",&t);
for (int turn=1;turn<=t;turn++){
scanf ("%d",&n);
for (int i=1;i<=n;i++){
scanf ("%d",&num[i]);
dp[i]=num[i];
}
int qwe=1;
for (int i=n-1;i>=1;i--){
if (qwe>6) qwe=6;
for (int j=1;j<=qwe;j++){
dp[i]+=(double)(dp[i+j]/qwe);
}
qwe++;
}
printf("Case %d: %lf\n",turn,dp[1]);
}
return 0;
}
F - Aeroplane chess
题意:大富翁地图。丢筛子,两个格子间可能可以直接到达(不耗费时间)。只要最后超出终点就算到达。求到达的期望丢筛子次数。
解题思路:水题
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=10007;
const int maxn=2e5+5;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
double dp[maxn];
int qwe[maxn];
int main (){
int n,m,a,b;
while (~scanf ("%d%d",&n,&m)){
if (n==0&&m==0) break;
MT(dp,0);
MT(qwe,0);
for (int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
qwe[a]=b;
}
for (int i=n-1;i>=0;i--){
if (qwe[i]!=0){
dp[i]=dp[qwe[i]];
} else{
double tmp=0;
for (int j=i+1;j<=i+6;j++){
tmp+=dp[j];
}
dp[i]+=tmp/6;dp[i]+=1;
}
}
printf("%.4f\n",dp[0]);
}
return 0;
}
G - Bag of mice
题意:有一个袋子,袋子里面有w只白鼠,b只黑鼠。公主和龙轮流从袋子里抓老鼠,公主先抓。龙抓完老鼠后,随机跳出一只老鼠(不算龙抓的)。谁先抓到白鼠谁赢。求公主赢的概率。
解题思路:https://blog.csdn.net/weixin_44003265/article/details/103864741不想过去的人看图也行。
错误原因:我第一次看到这个题的时候,想正向推。每一次求抓白鼠的期望概率。显然,从第2次开始,就需要不停地使用前面的期望去修正这次的期望。正推是求不出来的(至少我是 ^ _ ^);
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=10007;
const int maxn=1e3+5;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
double dp[maxn][maxn];
int main (){
int w,b;
scanf ("%d%d",&w,&b);
MT(dp,0);
for (int i=1;i<=w;i++) dp[i][0]=1;
for (int i=1;i<=w;i++){
for (int j=1;j<=b;j++){
dp[i][j]=i*1.0/(i+j);
if (j>=2) dp[i][j]+=(j*1.0/(i+j)*(j-1)*1.0/(i+j-1)*i*1.0/(i+j-2))*dp[i-1][j-2];
if (j>=3) dp[i][j]+=(j*1.0/(i+j)*(j-1)*1.0/(i+j-1)*(j-2)*1.0/(i+j-2))*dp[i][j-3];
}
}
printf("%.9f\n",dp[w][b]);
return 0;
}