注意:在概率DP中求期望要逆着推,求概率要正着推

概率DP求期望:

链接: http://acm.hdu.edu.cn/showproblem.php?pid=4405

dp[ i ]表示从i点走到n点的期望,在正常情况下i点可以到走到i+1,i+2,i+3,i+4,i+5,i+6 点且每个点的概率都为1/6

所以dp[i]=(dp[i+1]+dp[i+2]+dp[i+3]+dp[i+4]+dp[i+5]+dp[i+6])/6  + 1(步数加一)

而对于有跳跃的点直接为dp[a]=dp[b];

</pre><pre code_snippet_id="436469" snippet_file_name="blog_20140727_1_1601949" name="code" class="cpp">
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100000+10;
double dp[maxn];
int vist[maxn];
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0)
break;
memset(vist,-1,sizeof(vist));
memset(dp,0.0,sizeof(dp));
int a,b;
while(m--)
{
cin>>a>>b;
vist[a]=b;
}
for(int i=n-1;i>=0;i--)
{
if(vist[i]!=-1) dp[i]=dp[vist[i]];
else
{
dp[i]=(dp[i+1]+dp[i+2]+dp[i+3]+dp[i+4]+dp[i+5]+dp[i+6])/6.0+1;
}
}
printf("%.4lf\n",dp[0]);
}
return 0;
}

直接推到公式求期望:

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3853

题目大意

有一个人被困在一个 R*C(2<=R,C<=1000) 的迷宫中,起初他在 (1,1) 这个点,迷宫的出口是 (R,C)。在迷宫的每一个格子中,他能花费 2 个魔法值开启传送通道。假设他在
(x,y) 这个格子中,开启传送通道之后,有 p_lift[i][j] 的概率被送到 (x,y+1),有 p_down[i][j] 的概率被送到 (x+1,y),有 p_loop[i][j] 的概率被送到 (x,y)。问他到出口需要花费的魔法值的期望是多少。

做法分析

令:f[i][j] 表示从 (i,j) 这个点到出口 (R,C) 花费的魔法值的期望。

那么,我们有:

f[i][j] = p_loop[i][j]*f[i][j] + p_left[i][j]*f[i][j+1] + p_down[i][j]*f[i+1][j]

移项可得:

(1-p_loop[i][j])*f[i][j] = p_left[i][j](f[i][j+1] + p_down[i][j]*f[i+1][j]

于是我们可以倒着递推了

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000+10;
double dp[maxn][maxn];
typedef struct Mat
{
double a,b,c;
};
Mat p[maxn][maxn];
int main()
{
int r,c;
while(scanf("%d%d",&r,&c)!=EOF)
{
if(r==0&&c==0) break;
for(int i=0;i<r;i++)
for(int j=0;j<c;j++)
scanf("%lf%lf%lf",&p[i][j].a,&p[i][j].b,&p[i][j].c);
memset(dp,0.0,sizeof(dp));
for(int i=r-1;i>=0;i--)
for(int j=c-1;j>=0;j--)
{
if(i==r-1&&j==c-1) continue;
if(1-p[i][j].a==0) continue;
dp[i][j]=(1+dp[i][j+1]*p[i][j].b+dp[i+1][j]*p[i][j].c)/(1.0-p[i][j].a);
}
printf("%.3lf\n",2*dp[0][0]);
}
return 0;
}

直接推倒公式求期望

链接:http://poj.org/problem?id=2096

  1. dp求期望的题。
  2. 题意:一个软件有s个子系统,会产生n种bug。
  3. 某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中。
  4. 求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。
  5. 需要注意的是:bug的数量是无穷大的,所以发现一个bug,出现在某个子系统的概率是1/s,
  6. 属于某种类型的概率是1/n。
  7. 解法:
  8. dp[i][j]表示已经找到i种bug,并存在于j个子系统中,要达到目标状态的天数的期望。
  9. 显然,dp[n][s]=0,因为已经达到目标了。而dp[0][0]就是我们要求的答案。
  10. dp[i][j]状态可以转化成以下四种:
  11. dp[i][j]    发现一个bug属于已经找到的i种bug和j个子系统中
  12. dp[i+1][j]  发现一个bug属于新的一种bug,但属于已经找到的j种子系统
  13. dp[i][j+1]  发现一个bug属于已经找到的i种bug,但属于新的子系统
  14. dp[i+1][j+1]发现一个bug属于新的一种bug和新的一个子系统
  15. 以上四种的概率分别为:
  16. p1 =     i*j / (n*s)
  17. p2 = (n-i)*j / (n*s)
  18. p3 = i*(s-j) / (n*s)
  19. p4 = (n-i)*(s-j) / (n*s)
  20. 又有:期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E(aA+bB+...) = aE(A) + bE(B) +...
  21. 所以:
  22. dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + 1;
  23. 整理得:
  24. dp[i,j] = ( 1 + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] )/( 1-p1 )
  25. = ( n*s + (n-i)*j*dp[i+1,j] + i*(s-j)*dp[i,j+1] + (n-i)*(s-j)*dp[i+1,j+1] )/( n*s - i*j )
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000+10;
double dp[maxn][maxn];
int main()
{
int n,s;
cin>>n>>s;
dp[n][s]=0.0;
for(int i=n;i>=0;i--)
for(int j=s;j>=0;j--)
{
if(i==n&&j==s) continue;
dp[i][j]=(n*s+(n-i)*j*dp[i+1][j]+i*(s-j)*dp[i][j+1]+(s-j)*(n-i)*dp[i+1][j+1])/(n*s-i*j);
}
printf("%.4lf\n",dp[0][0]);
return 0;
}

先求概率在通过概率从求期望类型

链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2422

题解:《算法竞赛入门经典训练指南》141~142

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=110;
double dp[maxn][maxn];
int main()
{
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{
int a,b,n;
scanf("%d/%d%d",&a,&b,&n);
double p=(double)a/b;
memset(dp,0.0,sizeof(dp));
dp[0][0]=1.0;
dp[0][1]=0.0;
for(int i=1;i<=n;i++)
for(int j=0;b*j<=a*i;j++)
{
dp[i][j]=dp[i-1][j]*(1-p);
if(j) dp[i][j]+=dp[i-1][j-1]*p;
}
double Q=0.0;
for(int i=0;b*i<=a*n;i++)
Q+=dp[n][i];
printf("Case #%d: %d\n",cas,(int)(1/Q));
}
return 0;
}

DP专题之概率DP的更多相关文章

  1. DP专题·四(树形dp)

    1.poj 115 TELE 题意:一个树型网络上有n个结点,1~n-m为信号传送器,n-m+1~n为观众,当信号传送给观众后,观众会付费观看,每铺设一条道路需要一定费用.现在求以1为根,使得收到观众 ...

  2. AIM Tech Round 3 (Div. 1) (构造,树形dp,费用流,概率dp)

    B. Recover the String 大意: 求构造01字符串使得子序列00,01,10,11的个数恰好为$a_{00},a_{01},a_{10},a_{11}$ 挺简单的构造, 注意到可以通 ...

  3. Codeforces123E. Maze【树形dp】【概率dp】【证明题】

    LINK 题目大意 一棵树,上面的每个点都有一定概率成为起点和终点 从起点出发,随机游走,并按照下列规则统计count: DFS(x) if x == exit vertex then finish ...

  4. hdu3076—概率dp

    hdu3076-概率dp 标签 : 概率dp 题目链接 题意: 2个人分别有AB的血数,轮流扔骰子,数小的自减一血,平的不变,谁先到减0, 谁输,问A赢的概率. 题解: dp[i][j]表示的是第一个 ...

  5. 树形dp专题总结

    树形dp专题总结 大力dp的练习与晋升 原题均可以在网址上找到 技巧总结 1.换根大法 2.状态定义应只考虑考虑影响的关系 3.数据结构与dp的合理结合(T11) 4.抽直径解决求最长链的许多类问题( ...

  6. 概率dp作业

    概率dp特征: 概率DP一般求的是实际结果,在DP过程中,当前状态是由所有子状态的概率共同转移而来,所以概率DP只是利用了DP的动态而没有规划(即只需转移无需决策).-------qkoqhh A - ...

  7. UESTC 2015dp专题 F 邱老师看电影 概率dp

    邱老师看电影 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/65 Descr ...

  8. 【专题】概率期望DP

    11.22:保持更新状态:主要发一些相关的题目和个人理解 (P.S.如果觉得简单,可以直接看后面的题目) upd 11.30 更完了 [NO.1] UVA12230 Crossing Rivers  ...

  9. DP专题训练之HDU 2955 Robberies

    打算专题训练下DP,做一道帖一道吧~~现在的代码风格完全变了~~大概是懒了.所以.将就着看吧~哈哈 Description The aspiring Roy the Robber has seen a ...

随机推荐

  1. 【ITOO 3】.NET 动态建库建表:实用EF框架提供的codeFirst实现动态建库

    导读:在上篇博客中,介绍了使用SQL字符拼接的方式,实现动态建库建表的方法.这样做虽然也能够实现效果,但是,太麻烦,而且,如果改动表结构,字段的话,会对代码修改很多.但是EF给我们提供了一种代码先行的 ...

  2. [NOIP2001] 普及组

    装箱问题 裸01背包,速刷过 #include<cstdio> #include<iostream> #include<cmath> using namespace ...

  3. BZOJ1702: [Usaco2007 Mar]Gold Balanced Lineup 平衡的队列

    n<=100000个数表示每头牛在K<=30种物品的选取情况,该数在二进制下某位为0表示不选1表示选,求一个最大的区间使区间内选择每种物品的牛一样多. 数学转化,把不同状态间单变量的关系通 ...

  4. msp430入门编程12

    msp430中C语言的模块化头文件及库文件12 msp430入门学习 msp430入门编程

  5. as3 二维数组的定义

    大家都知道as3里面是不能直接定义多维数组 所以不能直接用arr[2][3]这样的方法来获取数组里面的值.如何才能创立多维数组了? 方法如下先定义一个数组 var MapData:Array=new ...

  6. python学习之-- 事件驱动模型

    目前主流的网络驱动模型:事件驱动模型 事件驱动模型:也属于生产者/消费者结构,通过一个队列,保存生产者触发的事件,队列另一头是一个循环从队列里不断的提取事件.大致流程如下:1:首先生成一个事件消息队列 ...

  7. loj516 DP一般看规律(set启发式合并)

    题目: https://loj.ac/problem/516 分析: 每次将一个颜色更改为另一个颜色相当于将两个集合合并 然后对于答案的更新,一个点插入到一个集合中,那么可能更新答案的就是其前驱节点或 ...

  8. 【Todo】C++和Java里面的浮点数及各种数字表示

    今天看了这篇文章,是讲C++中的浮点类型的:<浮点数的二进制表示> 再复习一下Java里面的Float和Double. 首先,直接数字赋值给Float变量是不行的,数字后要加上F,这样写: ...

  9. [转]JS 引擎的执行机制

    转: https://www.cnblogs.com/wancheng7/p/8321418.html ------------------------------------------------ ...

  10. 转: 将Eclipse代码导入到AndroidStudio的两种方式

    评注: 讲解的非常之详细 转自:    http://www.cnblogs.com/ct2011/p/4183553.html 说到使用AndroidStudio,除了新建的项目,我们都会面临的问题 ...