概率与期望DP,一直都不会啊,感觉好难完全没法思考…
期望题一般是逆推,当然也有一些是顺推,然而现在我只做过一些水得很的期望题,好菜啊…
UVa 11021 麻球繁衍 蓝书p140
题解:
现在有k只麻球,每只麻球都只能活一天,但是可能会在死前爆出0到n-1值麻球,几率分别为 p0,p1,p2...pn−1 ,求m天后所有麻球都死了的概率,因为每只麻球是独立的,这只麻球并不会导致另一只麻球死掉,也不会让另一只麻球少生几个麻球,所以我们只需要管最开始有1只麻球,然后最后用乘法原理即可,也就是第一只麻球死完的概率乘以第二只麻球死完的概率一直乘到第k只麻球死完的概率,如果有没有死的那就不行了。
问题转化为一只麻球在m天死完的概率,于是我们发现,在第i天死完的几率为生一个蛋的几率乘以(这一个蛋在)第i-1天死完的几率+生两个蛋的几率乘以(整两个蛋)在第i-1天死完的几率,也就是一个蛋在i-1天死完的几率乘以一个蛋在i-1天死完的几率。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int T,n,k,m;
const int MAXN=1000+10;
double p[MAXN],dp[MAXN];
double fast_pow(double num,int k){
double now=num;
double ans=1.0;
while(k){
if(k&1) ans*=now;
now*=now;k>>=1;
}
return ans;
}
int main(){
scanf("%d",&T);
for(register int kase=1;kase<=T;kase++){
scanf("%d%d%d",&n,&k,&m);
for(register int i=0;i<=n-1;i++) scanf("%lf",&p[i]);
dp[0]=0;dp[1]=p[0];
for(register int i=2;i<=m;i++){
dp[i]=0;
for(register int j=0;j<=n-1;j++){
dp[i]+=p[j]*pow(dp[i-1],j);
}
}
double ans=fast_pow(dp[m],k);
printf("Case #%d: %0.7lf\n",kase,ans);
}
return 0;
}
UVa 11427 玩纸牌
这道题貌似很水,蓝书p141,我自己都写出来了,就是说我们要求的是一天晚上玩儿停了的概率,那么我们用1除以这个概率就可以了
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int T,n,a,b;
double p,dp[110][110];
int main(){
scanf("%d",&T);
for(register int kase=1;kase<=T;kase++){
scanf("%d/%d %d",&a,&b,&n);
p=(double)a/b;
memset(dp,0,sizeof(dp));
dp[0][0]=1.0;dp[0][1]=0.0;//在地0局,赢0局的概率为1,在第0局,赢1局的概率为0
for(register int i=1;i<=n;i++)
for(register int i=1;i<=n;i++){
//一共玩儿的局数应该小于a/b,故j/i<=a/b,即j*b<=i*a
for(register int j=0;j*b<=i*a;j++){
if(j==0){
dp[i][j]=dp[i-1][j]*(1.0-p);
continue;
}
dp[i][j]=dp[i-1][j]*(1.0-p)+dp[i-1][j-1]*p;
}
}
double ans=0.0;
for(register int j=0;j*b<=a*n;j++)
ans+=dp[n][j];
int final=floor(1/ans);
printf("Case #%d: %d\n",kase,final);
}
return 0;
}