[关闭]
@01010101 2018-10-18T08:26:16.000000Z 字数 3456 阅读 1414

概率dp总结

总结


参考:
https://www.cnblogs.com/hua-dong/p/8166093.html
https://blog.csdn.net/iceprincess_1968/article/details/80157137
https://blog.sengxian.com/algorithms/probability-and-expected-value-dynamic-programming

SPOJ Favorite Dice
题意:甩一个n面的骰子,问每一面都被甩到的次数期望是多少。

dp[i]:已经抛出i面,为使每一面都被抛到,还要抛的期望。

化简即可。

SGU 495
题意:n个盒子里装有礼物,m个人随机选择礼物,选完之后将盒子放回.问所有人选中的礼物数的期望。

法一:
m个人是独立的。
对于每个礼物不被人选中的概率为((n-1)/n)^m
那么不被选中的礼物数的期望就是 n*((n-1)/n)^m
所以答案就是 n-n*((n-1)/n)^m;
法二:
dp[i]:第i个人得到礼物的概率
第i个人得到礼物的概率:
假如第i-1个人没有得到礼物,那么i得到礼物的概率和i-1一样。
假如第i-1个人得到了礼物,那么i得到礼物的概率是i-1得到礼物概率减去1/n

Uva12230Crossing Rivers
题目大意:
有个人每天要去公司上班,每次会经过N条河,家和公司的距离为D,默认在陆地的速度为1,
给出N条河的信息,包括起始坐标p,宽度L,以及船的速度v。船会往返在河的两岸,人到达河岸时,
船的位置是随机的(往返中)。问说人达到公司所需要的期望时间。

需要判断的只有过河的时间。而船的位置是随机的,所以:
1,过每条河最坏的情况是t=3*L/v; 即去的时候船刚刚走。
2,过没条河最优的情况是t=L/v; 即去的时候船刚刚来。
3,由于船是均匀发布的,符合线性性质,所以平均下来,过每条河的时间t=2*L/v。

51Nod 1705 七星剑
题意:你要把一把剑从0星升至7星,有n颗宝石供你选择,第i颗宝石的价值是c[i],在炼化第k颗星的时候,用魔法石i将有p(k,i)的机率成功,即炼化后剑上从原有的(k-1)颗星变成k颗星。但是如果失败不但不会多出星来还会丢失los(k,i)颗星(0<=lose(k,i)<=k-1),当然这次使用的魔法石也会被毁坏)。求打造七星剑花费的期望的最小值。

第一想法的状态是:
dp[i][j]:用第j中宝石炼化第i颗星,炼化剩下的星的期望。
于是方程显然。
dp[i][j]=dp[i+1][k]p[i][j]+dp[i-los[i][j]][k](1-p[i][j])+c[j];
然后就发现成环了。逆推就只能用高斯消元了。

所以考虑正推。
dp[i][j]:从第i颗星升级至第j颗星的期望。这样状态就是可加的。
dp[i][j]=min{c+p*dp[i+1][j]+(1-p)*dp[i-los][j]}
不满足条件的就是dp[i-los][j],但它可以变成dp[i-los][i]+dp[i][j];

注意-1的情况不能在最后判断,因为即使inf也可以更新下一个的值。
注意枚举顺序。
注意:从有i颗星升级成j颗星,当前炼化的是第i+1颗星。

  1. for(int j=1;j<=m;++j){
  2. for(int i=j-1;i>=0;--i){
  3. dp[i][j]=inf;
  4. for(int k=1;k<=n;++k){
  5. dp[i][j]=min((c[k]+p[i+1][k]*dp[i+1][j]+(1-p[i+1][k])*dp[i-los[i+1][k]][i])/p[i+1][k],dp[i][j]);//!!
  6. }
  7. }
  8. }

BZOJ3450: Easy
题意:给定一个序列,仅包含'o','x','?'。‘o’代表长度加1,'x'代表长度清0,‘?’位置未确定(即'o'和'x'的概率分别为0.5)。对于一个 ox? 序列,连续 k 长度会有k^2的收益,求最终得到的序列的期望收益。

dp[i]:长度为i的期望收益.
这题的初始状态和初值好确定:dp[0]=0,而终值就是所求的答案。所以我们顺推计算。
注意码代码时,,dp[i-1]+1不可替换成dp[i].如果替换,概率就重复计算了。

  1. for(int i=1;i<=n;++i){
  2. if(s[i]=='o') {
  3. dp[i]=dp[i-1]+1;
  4. ans+=dp[i]*dp[i]-dp[i-1]*dp[i-1];
  5. }
  6. else if(s[i]=='?'){
  7. dp[i]=0.5*(dp[i-1]+1);
  8. ans+=0.5*((dp[i-1]+1)*(dp[i-1]+1)-dp[i-1]*dp[i-1]);//!!
  9. }
  10. else dp[i]=0;
  11. }

BZOJ4318: OSU!
给出一个01序列。在这个串中连续的X个1可以贡献X^3 的分数。求期望分数。

和上道题一样,只是x^2的分数变成了x^3的分数。
注释掉的那里注意:长度期望的平方不等于长度平方期望。我们要的是长度期望的平方。立方同理。不过在代码中将化简了。

  1. for(int i=1;i<=n;++i){
  2. dp[i]=p[i]*(dp[i-1]+1);
  3. // dp1[i]=p[i]*(dp[i-1]+1)*(dp[i-1]+1);
  4. dp1[i]=p[i]*(dp1[i-1]+2*dp[i-1]+1);
  5. ans+=p[i]*(dp1[i-1]*3+dp[i-1]*3+1);
  6. }

51Nod 1450
闯关游戏
有N个游戏。玩家可以任意时刻玩任意一个小游戏,且每个游戏可以玩任意多次,一个游戏玩一次是1min。玩家可以多次挑战同一个小游戏,而且系统只会记录玩家多次挑战中的最好成绩。
根据一些统计,一个玩家在任一次玩第i个小游戏时,都会独立的发生以下结果:
* 有(1000 - Xi - Yi)*0.001的概率会挑战失败;
* 有 Xi*0.001 的概率会挑战成功并获得一颗星;
* 有 Yi*0.001 的概率会挑战成功并获得两颗星.
通关条件:1)N个小游戏的系统记录的最好成绩都是成功;2)这N个小游戏的系统记录成绩中的星星总数至少是M颗。
求最优策略下需要花费时间的期望E。

题目上有几个提示:1.采用最优策略(贪心),2.星的计算只记录最好成绩。
所以我们不能直接设状态为dp[i][j],表示过前i关,得到j颗星,通关的最小期望时间; 转移是:dp[i][j]=(1+dp[i+1][j+2]*y[i+1]+dp[i+1][j+1]*x[i+1])/(x[i+1]+y[i+1]);
因为如果一关只能不通关或者得一颗星,打再多次也只能得一颗星。而如果是当前已经是两颗星了,打再多次也不能出现一颗星。
所以要单独考虑得到两颗星的情况。用y大的刷星。

  1. int main(){
  2. // freopen("a.txt","r",stdin);
  3. scanf("%d%d",&n,&m);
  4. for(int i=1;i<=n;++i) scanf("%lf%lf",&a[i].x,&a[i].y);
  5. sort(a+1,a+n+1);
  6. m-=n;
  7. for(int i=0;i<m;++i) dp[n][i]=inf;
  8. for(int i=n-1;i>=0;--i){
  9. double c=a[i+1].x+a[i+1].y;
  10. for(int j=0;j<m;++j)
  11. dp[i][j]=min(1000/c+a[i+1].x/c*dp[i+1][j]+a[i+1].y/c*dp[i+1][j+1],1000/a[i+1].y+dp[i+1][j+1]);
  12. dp[i][m]=1000/c+dp[i+1][m];
  13. }
  14. printf("%.8f\n",dp[0][0]);
  15. return 0;
  16. }

期望 DP 一般来说有它固定的模式,一种模式是直接 DP,定义状态为到终点期望,采用逆序计算得到答案。一种模式是利用期望的线性性质,对贡献分别计算,这种模式一般要求我们求出每种代价的期望使用次数,而每种代价往往体现在 DP 的转移之中。最后的两个例题是典型的分离变量,用期望的线性性质计算答案的例子,如果状态过于巨大,那么就得考虑分离随机变量了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注