题目类型:期望\(DP\)

传送门:>Here<

题意:现有\(N\)个时间段,每个时间段上一节课。如果不申请换教室,那么时间段\(i\)必须去教室\(c[i]\)上课,如果申请换课成功,那么就可以去教室\(d[i]\)上课。第\(i\)节课申请换教室成功的概率是\(k[i]\)。每个教室是无向图的一个节点,从一个教室到另一个教室需要耗费的体力是它们之间的最短路。现在,你最多可以申请换\(M\)节课,问耗费体力值最少的期望

解题思路

题意比较复杂。时间段不如理解为时间点。可以概括为:第\(i\)个时间点要么在\(c[i]\)要么在\(d[i]\),并且到\(d[i]\)去的期望是\(k[i]\)。也就是说申请不成功的概率是\(1-k[i]\)

由于教室最多只有\(300\)间,因此最短路直接用\(Floyd\)处理即可。

然后考虑进行期望\(DP\)。容易想到设\(dp[i][j]\)表示前\(i\)个时间点里,申请\(j\)次的耗费体力值最少的期望。然而我们发现这样设非常难转移,因为我们不知道上一节课有没有换教室。

因此我们增加一维:\(dp[i][j][k]\)表示前\(i\)个时间点里,申请\(j\)次,并且\(k=0\)第\(i\)个时间点在\(c[i]\),\(k=1\)则在\(d[i]\)。这样就可以转移了

由于已经转化为\(DP\)问题,因此我们只需要考虑状态。分开考虑:

\[dp[i][j][0] = \begin{cases} dp[i-1][j][0] + dis[c[i-1]][c[i]]\\ dp[i-1][j][1] + (1-k[i-1])*dis[c[i-1]][c[i]] + k[i-1]*dis[d[i-1]][c[i]] \end{cases}
\]

对于\(dp[i][j][0]\)的转移,我们确定了在第\(i\)个时间点一定在教室\(c[i]\),而起点却不确定。分开考虑乘上概率即可

\[dp[i][j][1] = \begin{cases} dp[i-1][j-1][0] + (1-k[i])*dis[c[i-1]][c[i]] + k[i]*dis[c[i-1]][d[i]]\\ dp[i-1][j-1][1] +... \end{cases}
\]

第二个方程实在太长了(放不下……),可以见代码。总体思想还是和前面差不多,不一样的是\(dp[i][j][1]\)不能代表第\(i\)个时间点在教室\(d[i]\),而是都有可能,因此从\(dp[i-1][j-1][1]\)转移过来时要分四类讨论

Code

注意\(j=0\)也是要讨论的。另外,刚开始\(dp\)数组应该无限大,这样才能在转移时自动排除不可能的情况

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
using namespace std;
typedef long long ll;
const int MAXN = 2010;
const int MAXM = 20010;
const int INF = 1061109567;
inline int read(){
int x = 0; int w = 1; register char c = getchar();
for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
if(c == '-') w = -1, c = getchar();
for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int N,M,V,E,x,y,z;
int c[MAXN],d[MAXN],dis[305][305];
double k[MAXN],dp[MAXN][MAXN][2],ans;
int main(){
// freopen(".in","r",stdin);
memset(dis, 0x3f, sizeof(dis));
N = r, M = r, V = r, E = r;
for(int i = 1; i <= V; ++i) dis[i][i] = 0;
for(int i = 1; i <= N; ++i) c[i] = r;
for(int i = 1; i <= N; ++i) d[i] = r;
for(int i = 1; i <= N; ++i) scanf("%lf", k+i);
for(int i = 1; i <= E; ++i){
x = r, y = r, z = r;
dis[x][y] = min(dis[x][y], z);
dis[y][x] = min(dis[y][x], z);
}
for(int K = 1; K <= V; ++K){
for(int i = 1; i <= V; ++i){
for(int j = 1; j <= V; ++j){
dis[i][j] = min(dis[i][j], dis[i][K] + dis[K][j]);
}
}
}
for(int i = 1; i <= N; ++i){
for(int j = 0; j <= M; ++j){
dp[i][j][0] = dp[i][j][1] = 99999999.999;
}
}
dp[1][0][0] = dp[1][1][1] = 0;
for(int i = 2; i <= N; ++i){
dp[i][0][0] = dp[i-1][0][0] + dis[c[i-1]][c[i]];
for(int j = 1; j <= min(i,M); ++j){
dp[i][j][0] = min(dp[i-1][j][0] + dis[c[i-1]][c[i]], dp[i-1][j][1] + (1-k[i-1])*dis[c[i-1]][c[i]] + k[i-1]*dis[d[i-1]][c[i]]);
dp[i][j][1] = min(dp[i-1][j-1][0] + (1-k[i])*dis[c[i-1]][c[i]] + k[i]*dis[c[i-1]][d[i]], dp[i-1][j-1][1] + (1-k[i-1])*(1-k[i])*dis[c[i-1]][c[i]] + (1-k[i-1])*k[i]*dis[c[i-1]][d[i]] + k[i-1]*(1-k[i])*dis[d[i-1]][c[i]] + k[i-1]*k[i]*dis[d[i-1]][d[i]]);
}
}
ans = 9999999.999;
for(int j = 0; j <= M; ++j){
ans = min(ans, min(dp[N][j][0], dp[N][j][1]));
}
printf("%.2f", ans);
return 0;
}

[NOIp2016] 换教室的更多相关文章

  1. [NOIP2016]换教室 D1 T3 Floyed+期望DP

    [NOIP2016]换教室 D1 T3 Description 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第 ...

  2. BZOJ 4720 [Noip2016]换教室

    4720: [Noip2016]换教室 Description 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节课程安排在n个时间段上.在第i( ...

  3. 【BZOJ】4720: [Noip2016]换教室

    4720: [Noip2016]换教室 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1690  Solved: 979[Submit][Status ...

  4. bzoj4720: [Noip2016]换教室(期望dp)

    4720: [Noip2016]换教室 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1294  Solved: 698[Submit][Status ...

  5. [NOIP2016]换教室 题解(奇怪的三种状态)

    2558. [NOIP2016]换教室 [题目描述] 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第i(1< ...

  6. 【bzoj4720】[NOIP2016]换教室

    题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节课程安排在n个时间段上.在第i(1≤i≤n)个时间段上,两节内容相同的课程同时在不同的 ...

  7. [NOIP2016]换教室(概率期望$DP$)

    其实吧我老早就把这题切了--因为说实话,这道题确实不难啊--李云龙:比他娘的状压DP简单多了 今天我翻以前在Luogu上写的题解时,突然发现放错代码了,然后被一堆人\(hack\)--蓝瘦啊\(ORZ ...

  8. 【bzoj4720】[NOIP2016]换教室 期望dp

    题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节课程安排在n个时间段上.在第i(1≤i≤n)个时间段上,两节内容相同的课程同时在不同的 ...

  9. NOIP2016换教室 BZOJ 4720

    BZOJ 4720 换教室 题目描述: 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节 课程安排在n个时间段上.在第i(1≤i≤n)个时间段上 ...

随机推荐

  1. SAP MM 预留单据里的Base date和Requirement date

    SAP MM 预留单据里的Base date和Requirement date Base date可以在预留创建的初始界面指定, 这个日期可以作为预留各个行项目默认的requirement date. ...

  2. 【阿里云】在 Windows Server 2016 下使用 FileZilla Server 安装搭建 FTP 服务

     Windows Server 2016 下使用 FileZilla Server 安装搭建 FTP 服务 一.安装 Filezilla Server 下载最新版本的 Filezilla Server ...

  3. python 的with用途(清理资源和异常处理,同时代码精简)

    参考如下博客. https://www.cnblogs.com/DswCnblog/p/6126588.html #!/usr/bin/env python # with_example02.py c ...

  4. git第一次提交代码到码云

    转载请标明出处:https://www.cnblogs.com/tangZH/p/10229598.html 不说废话,来看重点. 1.首先注册码云账号,然后建立仓库,这些就直接跳过,很简单. 2.下 ...

  5. 配置ADB到Windows环境变量

    adb 命令可以帮我们快速的管理连接的手机设备,例如执行一些安装apk,卸载apk命令,对于熟悉linux系统的人,可以方便的管理手机目录操作手机文件,还可以通过adb命令查看手机的系统日志等操作. ...

  6. PJSUA2开发文档--第九章 PJSUA2应用程序示例

    9. PJSUA2示例应用程序 9.1 示例应用程序 9.1.1 C++ pjsip-apps/src/samples/pjsua2_demo.cpp 是一个非常简单可用的C++示例应用程序. /* ...

  7. Redis(十一):Redis的事务功能详解

    相关命令 1. MULTI 用于标记事务块的开始.Redis会将后续的命令逐个放入队列中,然后才能使用EXEC命令原子化地执行这个命令序列. 这个命令的运行格式如下所示: MULTI 这个命令的返回值 ...

  8. 【原】Java学习笔记009 - 阶段测试

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 1.需求:打印如下 ...

  9. LeetCode算法题-Second Minimum Node In a Binary Tree(Java实现)

    这是悦乐书的第285次更新,第302篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第153题(顺位题号是671).给定非空的特殊二叉树,其由具有非负值的节点组成,其中该树 ...

  10. 英语词性系列-B02-动词

    诗Poem 要求:背诵这首诗,翻译现代文,根据现代文用简单的英文翻译. 动词直观体会 动词 动词 动词 动词 动词 sell卖 buy买 beat击打 look看 dance跳舞 sing唱歌 spe ...