做完这道题才略微感觉自己懂了一点关于概率与期望的知识QAQ。。。

一:关于概率与期望的定义

转载节选于blog

1、什么是数学期望?

数学期望亦称期望、期望值等。在概率论和统计学中,一个离散型随机变量的期望值是试验中每一次可能出现的结果的概率乘以其结果的总和。

这是什么意思呢?假如我们来玩一个游戏,一共52张牌,其中有4个A。我们1元钱赌一把,如果你抽中了A,那么我给你10元钱,否则你的1元钱就输给我了。在这个游戏中,抽中的概率是113(452)

,结果是赢10元钱;抽不中概率是1213,结果是亏1元钱。那么你赢的概率,也就是期望值是−213。这样,你玩了很多把之后,一算账,发现平均每把会亏−213

元。

一般在竞赛中,若X是一个离散型的随机变量,可能值为x1,x2

……,对应概率为p1,p2……,概率和为1,那么期望值E(X)=∑ipixi

对于数学期望,我们还应该明确一些知识点:

(1)期望的“线性”性质。对于所有满足条件的离散型的随机变量X,Y和常量a,b,有:E(aX+bY)=aE(x)+bE(y)

类似的,我们还有E(XY)=E(X)+E(Y)

(2)全概率公式 假设{Bn∣n=1,2,3,...

}是一个“概率空间有限或可数无限”的分割,且集合Bn

是一个“可数集合”,则对于任意事件A有:

P(A)=∑nP(A∣Bn)P(Bn)

(3)全期望公式 E(Y)=E(E(Y∣X))=∑iP(X=xi)E(Y∣X=xi)

2、数学期望怎么用?

确实,数学期望在数学的范围里是一个较为复杂,但是却十分有用的一个部分。

但是题型类型多,花样也多,有时无从下手。明知是数学期望,却找不到正确的算法解决问题。

于是,我们来分析一下:

(1)对于很大一部分的期望问题,递推是个好帮手。我们一般在草稿纸上,把题目中隐含的期望值之间的关系,然后经过计算等方法,找出一个递推式。这个递推式,不要求我们枚举每一种可能(不然就没有用递推的意义了),而是根据一些已有的,或是可以直接简单地推算出的期望值,算出其他状态下的期望。这个道理道理大家也都明白,可是有时是很难找到递推式的。这时,我们就应该用我们之前讲过的期望的定义——E(X)=∑ipixi

,然后再结合期望的“线性”性质和全概率、全期望公式,一步步地像“剥笋皮”一样,找到问题的核心,这样效果往往很好。

(2)另外,有决策、满足最优子结构的期望问题,我们还可以考虑人们常常与“递推”弄混的“动态规划”。这里,我们一般用期望表示状态,期望的正负高低,就能决定这个状态的优和劣。

(3)对于上述两种方法都不能解决的,这也算是比较少了。这时,常见的尝试方法之一就是高斯消元法。我们可以先尝试建立一个线性方程组,然后进行高斯消元等操作

其实以上的理论我看着也。。。。

也给大家推荐一个blog,里面有许多的关于这个专题的详解和例题。

二:关于此题。。。

1、题目大意:

有一个v个节点的无向图,共有e条边,牛牛应该上n节课,第i课同时在c[i]与d[i]进行,牛牛都可以去上,唯一的区别是在c[i]上课不需要申请而在d[i]则需要,并且仅有m次机会申请,通过概率为p[i];要求的就是牛牛移动的体力值总和的期望值最小。

2、大概思路

(1)初始化

首先就是对于这v个点之间的最短路径进行处理,因为仅仅有300个点,所以即使用Floyd也不会爆掉,但是感人感觉用v遍优先队列优化的Dij会更稳一些,这里给出代码

void dij(int x)
{
memset(vis,false,sizeof(vis));
for(int i=1;i<=v;i++)
dis[x][i]=INF;
q.push(mp(0,x));
dis[x][x]=0;
while(!q.empty())
{
int y=q.top().second;
q.pop();
if(vis[y]) continue;
vis[y]=true;
for(int i=head[y];i;i=nxt[i])
if(dis[x][ver[i]]>dis[x][y]+eage[i])
{
dis[x][ver[i]]=dis[x][y]+eage[i];
q.push(mp(-dis[x][ver[i]],ver[i]));
}
}
}

对于路径储存,有兴趣的可以学一下vector+pair储存blog

其次便是对于dp数组f的初始化了

f[i][j][k]表示在前i节课,申请j次,且用k表示第i次有无申请;一定要注意这个地方k表示的不是是否申请成功而是有无申请,在这个地方卡了好久orz。

因为要求最小值所以把f都赋值成极大值

f[1][0][0]与f[1][1][1]以为是初始位置所以都是0。

此外还要注意在第i次的时候要先处理一下j=0的情况

即f[i][0][0]=f[i-1][0][0]+dis[c[i-1]][c[i]];

牛牛从未申请过所以直接拿f[i-1][0][0]加c[i-1]与c[i]的距离就可以了。

(2)算法主体

f[i][j][0]就可以等于以下两种的较小值

  1. 上一次未申请的f[i-1][j][0]加上c[i]与c[i-1]的距离;
  2. 上一次申请的f[i-1][j][1]有p[i-1]的概率申请成功,有(1-p[i-1])的概率申请失败,所以应该为f[i-1][j][1]与p[i-1]dis[c[i]][d[i-1]]+(1-p[i-1])dis[c[i]][c[i-1]]的和。

同样的f[i][j][1]也有p[i]的概率成功,就可以等于以下两种的较小值

  1. 上一次未申请的f[i-1][j-1][0]+p[i]dis[c[i-1]][d[i]]+(1-p[i])dis[c[i-1]][c[i]];
  2. 上一次申请的f[i-1][j-1][1]+p[i](p[i-1]dis[d[i-1]][d[i]]+(1-p[i-1])dis[c[i-1]][d[i]])+(1-p[i])(p[i-1]dis[d[i-1]][c[i]]+(1-p[i-1])dis[c[i-1]][c[i]]。

(3)输出

求出前n个中申请1-m次的最小值

for(int i=0;i<=m;i++)
ans=min(ans,min(f[n][i][0],f[n][i][1]));
printf("%.2lf",ans);

3、CODE

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
using namespace std;
const int N=9e4;
const int INF=1e9;
int n,m,v,e,tot,head[2*N+5],nxt[2*N+5],eage[2*N+5],ver[2*N+5],c[2005],d[2005];
double p[2005],f[2005][2005][2],dis[2005][2005],ans=INF;
bool vis[2005];
priority_queue<pair<int,int> > q;
void add(int x,int y,int t)
{
ver[++tot]=y,eage[tot]=t;
nxt[tot]=head[x],head[x]=tot;
}
void dij(int x)
{
memset(vis,false,sizeof(vis));
for(int i=1;i<=v;i++)
dis[x][i]=INF;
q.push(mp(0,x));
dis[x][x]=0;
while(!q.empty())
{
int y=q.top().second;
q.pop();
if(vis[y]) continue;
vis[y]=true;
for(int i=head[y];i;i=nxt[i])
if(dis[x][ver[i]]>dis[x][y]+eage[i])
{
dis[x][ver[i]]=dis[x][y]+eage[i];
q.push(mp(-dis[x][ver[i]],ver[i]));
}
}
}
void init()
{
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",&p[i]);
for(int i=1,x,y,t;i<=e;i++)
{
scanf("%d%d%d",&x,&y,&t);
add(x,y,t);
add(y,x,t);
}
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
f[i][j][0]=f[i][j][1]=INF;
f[1][0][0]=f[1][1][1]=0;
}
int main()
{
init();
for(int i=1;i<=v;i++)
dij(i);
for(int i=2;i<=n;i++)
{
f[i][0][0]=f[i-1][0][0]+dis[c[i-1]][c[i]];
for(int j=1;j<=min(i,m);j++)
{
f[i][j][0]=min(f[i][j][0],min(f[i-1][j][0]+dis[c[i]][c[i-1]],f[i-1][j][1]+p[i-1]*dis[c[i]][d[i-1]]+(1-p[i-1])*dis[c[i]][c[i-1]]));
f[i][j][1]=min(f[i-1][j-1][0]+p[i]*dis[c[i-1]][d[i]]+(1-p[i])*dis[c[i-1]][c[i]],f[i-1][j-1][1]+p[i]*(p[i-1]*dis[d[i-1]][d[i]]+(1-p[i-1])*dis[c[i-1]][d[i]])+(1-p[i])*(p[i-1]*dis[d[i-1]][c[i]]+(1-p[i-1])*dis[c[i-1]][c[i]])); }
}
for(int i=0;i<=m;i++)
ans=min(ans,min(f[n][i][0],f[n][i][1]));
printf("%.2lf",ans);
return 0;
}

题解 P1850 [NOIP2016 提高组] 换教室的更多相关文章

  1. Luogu P1850 [NOIp2016提高组]换教室 | 期望dp

    题目链接 思路: <1>概率与期望期望=情况①的值*情况①的概率+情况②的值*情况②的概率+--+情况n的值*情况n的概率举个例子,抛一个骰子,每一面朝上的概率都是1/6,则这一个骰子落地 ...

  2. [NOIp2016提高组]换教室

    题目大意: 有n节课,第i节课在c[i]上课,同时d[i]也有一节课d[i]. 你有权利向教务处发出m次申请把自己的教室改到d[i],相应的批准概率是k[i]. 教室是图上的一些点,其中每条边都有边权 ...

  3. 洛谷 1850 NOIP2016提高组 换教室

    [题解] 先用floyed处理出两点间的最短路. 设f[i][j][k]表示走到第i个教室,总共换了j次,当前换或者不换,期望的最小移动距离. 分情况讨论来转移即可. #include<cstd ...

  4. 【题解】NOIP2016提高组 复赛

    [题解]NOIP2016提高组 复赛 传送门: 玩具谜题 \(\text{[P1563]}\) 天天爱跑步 \(\text{[P1600]}\) 换教室 \(\text{[P1850]}\) 组合数问 ...

  5. 【题解】NOIP2016 提高组 简要题解

    [题解]NOIP2016 提高组 简要题解 玩具迷题(送分) 用异或实现 //@winlere #include<iostream> #include<cstdio> #inc ...

  6. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  7. 【题解】NOIP2015提高组 复赛

    [题解]NOIP2015提高组 复赛 传送门: 神奇的幻方 \([P2615]\) 信息传递 \([P2661]\) 斗地主 \([P2668]\) 跳石头 \([P2678]\) 子串 \([P26 ...

  8. 【题解】NOIP2017 提高组 简要题解

    [题解]NOIP2017 提高组 简要题解 小凯的疑惑(数论) 不讲 时间复杂度 大力模拟 奶酪 并查集模板题 宝藏 最优解一定存在一种构造方法是按照深度一步步生成所有的联通性. 枚举一个根,随后设\ ...

  9. [日记&做题记录]-Noip2016提高组复赛 倒数十天

    写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...

随机推荐

  1. Vue中的MVVM

    MVVM(Model View VueModel) View层: 视图层 在我们前端开发中,通常就是DOM层 主要的作用就是给用户展示各种信息 Model层: 数据层 数据可能是我们固定的死数据,更多 ...

  2. MFC的六大机制

    MFC的六大机制 程序的初始化过程 运行时类型识别 动态创建 永久保存 消息映射 命令传递 运行时类型识别 MFC的运行时类型识别就是在程序运行过程中判断某个对象是否属于某个类,MFC通过为需要进行运 ...

  3. C++ primer plus读书笔记——第2章 开始学习C++

    第2章 开始学习C++ 1. endl确保程序继续运行前刷新输出(将其立即显示在屏幕上),而使用"\n"不提供这样的保证,这意味着在有些系统中,有时可能在您输入信息后才会出现提示. ...

  4. [Django框架之视图层]

    [Django框架之视图层] 视图层 Django视图层, 视图就是Django项目下的views.py文件,它的内部是一系列的函数或者是类,用来专门处理客户端访问请求后处理请求并且返回相应的数据,相 ...

  5. linux 视频输出xrandr设置命令

    linux 视频输出xrandr设置命令 沈祥佑关注 0.592019.03.28 17:44:09字数 397阅读 6,886 xrandr 不带参数的xrandr 命令会列出系统支持的视频接口名称 ...

  6. VMware(Caps Lock键)切换大小写作用失效的Bug的解决办法

    前言 第一种情况是:进入VMware虚拟机的时候,即使按了Capslock键开启大写,灯虽然亮了,但是,打出来的字母还是小写,没有有任何的效果,根本不能转换成大写. 只有按Shift+字母才能输入大写 ...

  7. 026.Python面向对象类的相关操作以及对象和类的删除操作

    类的相关操作 定义的类访问共有成员的成员和方法 定义的类动态添加公有成员的属性和方法 定义的类删除公有成员的属性和方法 1 定义一个基本的类 #定义一个类 class Plane(): #添加一个共有 ...

  8. Scala 函数式编程思想

    Spark 选择 Scala 作为开发语言 在 Spark 诞生之初,就有人诟病为什么 AMP 实验室选了一个如此小众的语言 - Scala,很多人还将原因归结为学院派的高冷,但后来事实证明,选择 S ...

  9. STM32F4-IAP学习笔记--(转)

    花了断断续续两天时间在STM32上面写了一个IAP(In Application Programing)Boot,期间多多少少还是遇到的了不少问题.现在就花点时间把这两天写的东西整理一下,就当是学习笔 ...

  10. redis的rehash过程

    在扩容和收缩的时候,如果哈希字典中有很多元素,一次性将这些键全部rehash到ht[1]的话,可能会导致服务器在一段时间内停止服务.所以,采用渐进式rehash的方式,详细步骤如下: 为ht[1]分配 ...