数学期望DP小结
2016-07-02 19:35
375 查看
最近刚学了数学期望DP,还是蛮恶心的,但是相比于其他DP还是比较好想的,主要思路和线性DP类似,主要注意的是概率计算利用加法原理加和的方式,还要注意避免数组下标为负的情况,需要进行平移。
Tyvj1864 守卫者的挑战
比较简单的一道数学概率DP,要注意负数组下标。
f[i][j][k] 表示 前i场 赢了j场 容量-地图为k的概率
然后状态转移是 :如果 赢了,i+1,j+1,k进行相应变化
输了,i+1, j不变,k不变
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的值要加的。
不知道为啥tyvj(垃圾OJ) printf会WA…
另外还有一道 tyvj1933好像也是数学期望的。。。
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 [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
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法