概率与期望dp

定义:

概率:事件A发生的可能性,计作P(A)

期望:事件A结果的平均大小,记住E(x)

​ E(x)=每种结果的大小与其概率的乘积的和

注意计算概率时需要考虑是否要用容斥原理

期望dp时注意有时要用倒序枚举

其实本质和其他的dp没什么区别

例题

概率充电器

题面

题意:n个充电元件由n-1条导线连通,每个充电原件自身是否直接充电以及每条导线是否导电都由概率决定,求进入充电状态的元件个数的期望

1<=n<=500000

树形换根概率dp,注意使用容斥原理

第一遍dfs:计算出f[i]表示由子树i通电的概率

第二遍dfs:计算出从父亲节点来电的概率,再用容斥原理加在一起

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
#define maxn 500100
int n;
int fir[maxn],nxt[maxn*2],vv[maxn*2];
double edge[maxn*2],q[maxn];
int tot=0;
double ans=0;
void add(int u,int v,double w)
{
nxt[++tot]=fir[u];
fir[u]=tot;
vv[tot]=v;
edge[tot]=w;
}
double h[maxn];
void dfs1(int u,int fa)
{
h[u]=q[u];
for(int i=fir[u];i;i=nxt[i])
{
int v=vv[i];
if(v==fa)continue;
dfs1(v,u);
h[u]=h[u]+h[v]*edge[i]-h[u]*h[v]*edge[i];
}
}
void dfs2(int u,int fa)
{
for(int i=fir[u];i;i=nxt[i])
{
int v=vv[i];
if(v==fa)continue;
if(fabs(1-h[v]*edge[i])>(1e-7))
{
double t=(h[u]-h[v]*edge[i])/(1-h[v]*edge[i]);
h[v]=h[v]+t*edge[i]-h[v]*t*edge[i];
ans+=h[v];
}else ans+=1;
dfs2(v,u);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int a,b;double p;scanf("%d%d%lf",&a,&b,&p);
add(a,b,p/100);add(b,a,p/100);
}
for(int i=1;i<=n;i++)scanf("%lf",&q[i]),q[i]/=100;
dfs1(1,0);
ans=h[1];
dfs2(1,0);
printf("%0.6lf",ans);
return 0;
}

换教室

题目

题意:小A的学校可以视为一个v个点的无向图,他有n门课程要按顺序上课,其中第i门课程要在节点ai进行,但还有一个备选地点bi。现在小A有m个申请机会,若申请第i门课,那么将有ki的概率使课程搬到bi进行。每门课最多申请一次,m次机会不必全部用完。他如何申请才能最小化在上课地点间移动的距离的期望值。求该期望值。

v<=300,n,m<=200

先用floyd求出任意两点的距离

再令f[i][j][0/1]表示前i节课申请m次且第i节课申请/不申请的最小期望值

注意double类型需要手动赋初值

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n,m,v,e;
double f[2010][2010],dp[2010][2010][2],k[2010];
int c[2010],d[2010];
double mymin(double x,double y)
{
return x<y?x:y;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
for(int i=1;i<=n;i++)scanf("%d",&d[i]);
for(int i=1;i<=n;i++)scanf("%lf",&k[i]);
for(int i=1;i<=v;i++)for(int j=1;j<=v;j++)f[i][j]=1e9;
for(int i=1;i<=v;i++)f[i][i]=0;
for(int i=1;i<=e;i++)
{
int a,b;double w;scanf("%d%d%lf",&a,&b,&w);
f[a][b]=f[b][a]=min(f[a][b],w);
}
for(int kk=1;kk<=v;kk++)
{
for(int i=1;i<=v;i++)
{
for(int j=1;j<=v;j++)
{
f[i][j]=f[j][i]=min(f[i][j],f[i][kk]+f[kk][j]);
}
}
}
for(int i=1;i<=n;i++)for(int j=0;j<=m;j++)
{
dp[i][j][0]=1e9;dp[i][j][1]=1e9;
}
dp[1][0][0]=dp[1][1][1]=0;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=min(m,i);j++)
{
dp[i][j][0]=mymin(dp[i-1][j][0]+f[c[i]][c[i-1]],dp[i-1][j][1]+k[i-1]*f[c[i]][d[i-1]]+(1-k[i-1])*f[c[i]][c[i-1]]);
if(j!=0)
dp[i][j][1]=mymin(dp[i-1][j-1][0]+f[c[i-1]][c[i]]*(1-k[i])+f[c[i-1]][d[i]]*k[i],dp[i-1][j-1][1]+f[c[i-1]][c[i]]*(1-k[i])*(1-k[i-1])+f[c[i-1]][d[i]]*(1-k[i-1])*k[i]+f[d[i-1]][c[i]]*k[i-1]*(1-k[i])+f[d[i-1]][d[i]]*k[i-1]*k[i]);
}
}
double ans=1e9;
for(int i=0;i<=m;i++)
{
ans=mymin(ans,dp[n][i][0]);ans=mymin(ans,dp[n][i][1]);
}
printf("%0.2lf",ans);
return 0;
}

奖励关

[题目]

题意:有n轮游戏和m种宝物,每种宝物有分数Pi(可以为负),每轮游戏会等概率抛出一种宝物,你可以选择吃或不吃。第i种宝物还有一个限制集合Si,表示只有在Si中的宝物都吃过后,才能吃第i种宝物。

1<=n<=100 1<=m<=15

期望状压dp

f[i][S]表示在第1轮到第i−1轮内宝物是否取过的状态为S,第i轮到第n轮的最大期望得分,进行逆推。

采用逆推的原因如下:

如果要从当前状态S0转移到目标状态S1,那么直接f[i+1][s1]+=f[i][s0]/n的转移方法是错误的,因为f[i+1][n]不一定有n种被转移到的方式,有可能因为限制集合的原因,有些状态不能转移到f[i+1][s],但如果采用逆推,那么我们是从一个合法的状态转移到当前状态,就不存在这样的问题,大多数期望dp都可以采用逆推的方法。

那么逆推如何转移呢:

枚举第k种宝物,可以取或不取,

如果能取,f[i][s]+=max(f[i+1][s],f[i+1][s|(1<<(k-1))]+p[k])

如果不能取,f[i][s]+=f[i+1][s]

然后f[i][s]/=n

答案为f[1][0]

#include <iostream>
#include <cstdio>
using namespace std;
int n,k;
double f[110][1<<18],value[110];
int sta[110];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++)
{
scanf("%lf",&value[i]);
int x;scanf("%d",&x);
while(x!=0)
{
sta[i]=sta[i]|(1<<(x-1));
scanf("%d",&x);
}
}
for(int i=n;i>=1;i--)
{
for(int j=0;j<=(1<<k)-1;j++)
{
for(int kk=1;kk<=k;kk++)
{
if((j|sta[kk])==j)
{
f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<(kk-1))]+value[kk]);
}
else f[i][j]+=f[i+1][j];
}
f[i][j]=(double)f[i][j]*1.0/k;
}
}
printf("%.6lf",f[1][0]);
return 0;
}

期望与概率dp的更多相关文章

  1. 【整理】简单的数学期望和概率DP

    数学期望 P=Σ每一种状态*对应的概率. 因为不可能枚举完所有的状态,有时也不可能枚举完,比如抛硬币,有可能一直是正面,etc.在没有接触数学期望时看到数学期望的题可能会觉得很阔怕(因为我高中就是这么 ...

  2. POJ2096Collecting Bugs(数学期望,概率DP)

    问题: Ivan is fond of collecting. Unlike other people who collect post stamps, coins or other material ...

  3. 动态规划之经典数学期望和概率DP

    起因:在一场训练赛上.有这么一题没做出来. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6829 题目大意:有三个人,他们分别有\(X,Y,Z\)块钱 ...

  4. 数学期望和概率DP题目泛做(为了对应AD的课件)

    题1: Uva 1636 Headshot 题目大意: 给出一个000111序列,注意实际上是环状的.问是0出现的概率大,还是当前是0,下一个还是0的概率大. 问题比较简单,注意比较大小: A/C & ...

  5. [转]概率DP总结 by kuangbin

    概率类题目一直比较弱,准备把kuangbin大师傅总结的这篇题刷一下! 我把下面的代码换成了自己的代码! 原文地址:http://www.cnblogs.com/kuangbin/archive/20 ...

  6. LOOPS 概率dp

    题意:迷宫是一个R*C的布局,每个格子中给出停留在原地,往右走一个,往下走一格的概率,起点在(1,1),终点在(R,C),每走一格消耗两点能量,求出最后所需要的能量期望 简单概率dp 注意   原地不 ...

  7. BZOJ 1415 [NOI2005]聪聪与可可 (概率DP+dfs)

    题目大意:给你一个无向联通图,节点数n<=1000.聪聪有一个机器人从C点出发向在M点的可可移动,去追赶并吃掉可可,在单位时间内,机器人会先朝离可可最近的节点移动1步,如果移动一步机器人并不能吃 ...

  8. poj 2096 Collecting Bugs (概率dp 天数期望)

    题目链接 题意: 一个人受雇于某公司要找出某个软件的bugs和subcomponents,这个软件一共有n个bugs和s个subcomponents,每次他都能同时随机发现1个bug和1个subcom ...

  9. zoj 3822 Domination (概率dp 天数期望)

    题目链接 参考博客:http://blog.csdn.net/napoleon_acm/article/details/40020297 题意:给定n*m的空棋盘 每一次在上面选择一个空的位置放置一枚 ...

随机推荐

  1. python如何切割字符串

    python字符串的分割方法如下 str.split():字符串分割函数 通过指定分隔符对字符串进行切片,并返回分割后的字符串列表. 语法: str.split(s, num)[n] 参数说明: s: ...

  2. Python基础 第四章 字典(1)

    通过名称来访问其各个值的数据结构,映射(mapping). 字典,是Python中唯一的内置映射类型,其中的值不按顺序排列,而是存储在键下.(键,可能是数.字符串.元组). 1.1 字典由 键 及其相 ...

  3. 从入门到自闭之Python解释器安装

    Python解释器的安装 1 下载 ​ 下载地址:https://www.python.org 选择windows平台的链接进行下载 https://www.python.org/downloads/ ...

  4. jsp页面报错,各种错误码意思

    基本原则: 2xx = Success(成功) 3xx = Redirect(重定向) 4xx = User error(客户端错误) 5xx = Server error(服务器端错误) 状态码 ( ...

  5. 【数据结构】P1310 表达式的值

    [题目链接] https://www.luogu.org/problem/P1310 题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. “× ”运算优先 ...

  6. 数值分析-Legendre正交多项式 实现函数逼近

    数值分析-Legendre正交多项式 实现函数逼近 2016年12月18日 21:27:54 冰三点水 阅读数 4057   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请 ...

  7. JS 实现继承的方法 ES6 and ES5

    继承 ES6 方法  (类的继承) ES6中有一个属性的 extends 语法: ​ • class Father {} ​ • class Son extends Father{} ​ 注意:是子类 ...

  8. Linux学习(一)-安装vm虚拟机以及如何在虚拟机上安装Centos系统

    (一)基本说明 学习Linux需要一个环境,我们需要创建一个虚拟机,然后在虚拟机上安装一个Centos系统来学习. 1)安装软件vm12; 2)通过vm12创建一个虚拟机空间; 3)在vm12创建好的 ...

  9. Linux下创建NFS来实现共享文件

    简介说明: 在项目生产环境我们经常需要实现文件共享,传统的常见方案是通过NFS,实现服务器之间共享某一块磁盘,通过网络传输将分散的文件集中存储在一块指定的共享磁盘,实现基本的文件共享.实现这种方案,分 ...

  10. 【python】python _、__、__xx__之间的差别

    本文来自 yzl11 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/yzl11/article/details/53792416?utm_source=copy 单下 ...