数学期望DP小结

最近刚学了数学期望DP,还是蛮恶心的,但是相比于其他DP还是比较好想的,主要思路和线性DP类似,主要注意的是概率计算利用加法原理加和的方式,还要注意避免数组下标为负的情况,需要进行平移。

  • Tyvj1864 守卫者的挑战
    比较简单的一道数学概率DP,要注意负数组下标。
    f[i][j][k] 表示 前i场 赢了j场 容量-地图为k的概率
    然后状态转移是 :如果 赢了,i+1,j+1,k进行相应变化
    输了,i+1, j不变,k不变
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=200+10;
int n,t,l;
double p[maxn];
int a[maxn];
double f[maxn][maxn][maxn+200]; // f[i][j][k]代表 前i场 赢了j场 容量-地图为k的概率 
int main(){
    scanf("%d%d%d",&n,&l,&t);
    for(int i=1;i<=n;i++){
        scanf("%lf",&p[i]);
        p[i]/=100;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    if(t>n)t=n;
    f[0][0][t+200]=1;            //k加200防止下标为负 
    for(int i=0;i<n;i++){
        for(int j=0;j<=n;j++){
            for(int k=-n;k<=n;k++){
                if(a[i+1]==-1){
                    f[i+1][j][k+200]+=f[i][j][k+200]*(1-p[i+1]);
                    f[i+1][j+1][k-1+200]+=f[i][j][k+200]*p[i+1];    
                }
                else {
                    f[i+1][j+1][min(k+a[i+1],n)+200]+=f[i][j][k+200]*p[i+1];
                    f[i+1][j][k+200]+=f[i][j][k+200]*(1-p[i+1]);
                }
            }
        }
    }
    double ans=0;
    for(int j=l;j<=n;j++){
        for(int k=0;k<=n;k++){
            ans+=f[n][j][k+200];    
        }
    }
    printf("%.6lf",ans);
    return 0;
}
  • Tyvj2002 扑克牌
    f[a][b][c][d][x][y]来记录当前已经翻了a张黑桃,b张红桃,c张梅花,d张方片,小王状态为x,大王状态为y时的期望值。x=4表示没有用过小王,x=0~3表示用过小王且变成相应的数。
    初始状态 f[0][0][0][0][4][4].翻到大小王要进行下判断,取一个最小值,要注意大小王翻过后sum的值要加的。
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
double f[20][20][20][20][5][5];
int vis[20][20][20][20][5][5];
int A,B,C,D;
double dp(int a,int b,int c,int d,int x,int y){

    if(vis[a][b][c][d][x][y]) return f[a][b][c][d][x][y];
    else vis[a][b][c][d][x][y]=1;

    int tot[4];
    tot[0]=a;tot[1]=b;tot[2]=c;tot[3]=d;
    tot[x]++;tot[y]++;

    if(tot[0]>=A&&tot[1]>=B&&tot[2]>=C&&tot[3]>=D) return f[a][b][c][d][x][y]=0.000;

    double ans=0;
    int sum=a+b+c+d;
    if(x!=4)sum++;
    if(y!=4)sum++;

    if(a<13) ans+=dp(a+1,b,c,d,x,y)*(13-a)/(54-sum);
    if(b<13) ans+=dp(a,b+1,c,d,x,y)*(13-b)/(54-sum);
    if(c<13) ans+=dp(a,b,c+1,d,x,y)*(13-c)/(54-sum);
    if(d<13) ans+=dp(a,b,c,d+1,x,y)*(13-d)/(54-sum);    

    if(x==4){
        double minnn=1000000;
        for(int i=0;i<=3;i++){
            minnn=min(minnn,dp(a,b,c,d,i,y)/(54-sum));  

        }ans+=minnn;
    }
    if(y==4){
        double minn2=1000000;
        for(int i=0;i<=3;i++){
            minn2=min(minn2,dp(a,b,c,d,x,i)/(54-sum));  

        }ans+=minn2;
    }

    f[a][b][c][d][x][y]=ans+1.000;
    return f[a][b][c][d][x][y];
}
int main(){
    scanf("%d%d%d%d",&A,&B,&C,&D);
    double goal=dp(0,0,0,0,4,4);
    if(goal>54) printf("-1.000");
    else
        //printf("%.3lf",goal);
        cout<<fixed<<setprecision(3)<<goal<<endl;
    return 0;
}

不知道为啥tyvj(垃圾OJ) printf会WA…

另外还有一道 tyvj1933好像也是数学期望的。。。

                                                  HelenKeller
                                                   2016.7.2
点赞