[NOIP2016]换教室(概率期望$DP$)
其实吧我老早就把这题切了……因为说实话,这道题确实不难啊……李云龙:比他娘的状压DP简单多了
今天我翻以前在Luogu上写的题解时,突然发现放错代码了,然后被一堆人\(hack\)……蓝瘦啊\(ORZ\)
嗯,还是有些点需要注意以下的!以下是今年4月写的:
\(\mathcal{\color{red}{Description}}\)
对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程。
在可以选择的课程中,有 \(2n\)节课程安排在 \(n\)个时间段上。在第$ i $(\(1 \leq i \leq n\))个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室\(c_i\)上课,而另一节课程在教室$ d_i$ 进行。
在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的 \(n\) 节安排好的课程。如果学生想更换第\(i\) 节课程的教室,则需要提出申请。若申请通过,学生就可以在第 i 个时间段去教室$ d_i$上课,否则仍然在教室 \(c_i\)上课。
由于更换教室的需求太多,申请不一定能获得通过。通过计算,牛牛发现申请更换第 \(i\) 节课程的教室时,申请被通过的概率是一个已知的实数 \(k_i\),并且对于不同课程的申请,被通过的概率是互相独立的。
学校规定,所有的申请只能在学期开始前一次性提交,并且每个人只能选择至多 \(m\)节课程进行申请。这意味着牛牛必须一次性决定是否申请更换每节课的教室,而不能根据某些课程的申请结果来决定其他课程是否申请;牛牛可以申请自己最希望更换教室的\(m\) 门课程,也可以不用完这 $m $个申请的机会,甚至可以一门课程都不申请。
因为不同的课程可能会被安排在不同的教室进行,所以牛牛需要利用课间时间从一间教室赶到另一间教室。
牛牛所在的大学有\(v\)个教室,有\(e\)条道路。每条道路连接两间教室,并且是可以双向通行的。由于道路的长度和拥堵程度不同,通过不同的道路耗费的体力可能会有所不同。 当第 \(i\) ( \(1 \leq i \leq n-1\))节课结束后,牛牛就会从这节课的教室出发,选择一条耗费体力最少的路径前往下一节课的教室。
现在牛牛想知道,申请哪几门课程可以使他因在教室间移动耗费的体力值的总和的期望值最小,请你帮他求出这个最小值。
\(\mathcal{\color{red}{Solution}}\)
那么对于这道题而言,先捋清楚题目是求什么的吧:
对于这个无向连通图,我们将每走一步定义为一个阶段。那么每一个阶段都有两种可能性:\(p_i\)的概率去\(d_i\),但是在所有的\(d[i]\) 中\((1<=i<=n)\)至多可以走\(m\)个,\((1-p_i)\)的概率去\(c[i]\)。而我们要求的,就是在这\(n\)个阶段结束之后的路程最小期望。
那么其实状态之间的转移,我们不难看出有两种状态的转移:从\(d[i-1]\)或从\(c[i-1]\)转移过来。而因为实际上对于这个\(DP\)而言,因为数据不大,所以不需要优化什么的\(qwq\),记录每种状态是可行的。
那么很显然啊,我们首先要预处理出每两个点之间的最短路来,方便状态的转移。而在这里,最简单的就是\(Floyd\)啊\(qwq\)。\((n^3\)显然可以接受\()\)
for(qwq int k=1;k<=v;k++)
for(qwq int i=1;i<=v;i++)
for(qwq int j=1;j<i;j++)
if(f[i][k]+f[k][j]<f[i][j])
f[i][j]=f[j][i]=f[i][k]+f[k][j];
然后就是\(DP\)方程了:
我们定义\(dp[i][j][0/1]\)来表示当前为第\(i\)个阶段,连同这一次已经用了\(j\)次换教室的机会,当前这次换\((1)\)不换\((0)\)的最小期望路程总和。
那么转移就可以如此转移:
这次不换:
\(dp[i][j][0]=\) \(min(\)上次不换的\(dp+\)这两次之间的路程 \(~~\), \(~~\)上次概率换了之后的\(dp+p[i]\times\)上次换了的教室与这次不换的教室之间的距离\(+(1-p[i])\times\)上次不换的教室与这次不换的教室之间的距离\()\)
“诶,为什么上次概率换了之后(即逗号之后的一大串)要加两个期望啊?”
这个问题就是\(rqy\)大佬给我解决的,现在我要农夫山泉一把了:因为在上一次换教室时是“概率”交换,所以不一定会换呀。所以要把两种情况的都加上\(qwq\)。
到这儿我们就可以发现,其实换教室比不换教室是要多一重状态的,因为换教室总要牵扯“概率成功”的问题\(qwq\)
那其实接下来的状态转移方程就很简单了:一次换一次不换,遇到不换就\((1-p[i])\),遇到换就\(p[i]\);两次都不换就不用枚举概率。而且由于牵扯到两次都是概率性事件(比如两次都换)之类的,这个时候需要的就是乘法原理了。
那么\(DP\)即如下:
#define qwq register
for(qwq int i=1;i<=n;i++)
for(qwq int j=0;j<=m;j++)
dp[i][j][0]=dp[i][j][1]=999999999;
dp[1][0][0]=dp[1][1][1]=0;
for(qwq int i=2;i<=n;i++){
double dist1=f[c[i-1]][c[i]],dist2=f[d[i-1]][c[i]],dist3=f[c[i-1]][d[i]];
for(qwq int j=0;j<=min(m,i);j++)
{
dp[i][j][0]=min(dp[i-1][j][0]+dist1,dp[i-1][j][1]+dist2*p[i-1]+dist1*(1-p[i-1]));
if(j!=0)
dp[i][j][1]=min(dp[i-1][j-1][0]+dist3*p[i]+dist1*(1-p[i]),dp[i-1][j-1][1]+dist1*(1-p[i-1])*(1-p[i])+dist3*(1-p[i-1])*p[i]+dist2*(1-p[i])*p[i-1]+dist2*p[i-1]*p[i]);
}
}
总结:遇到期望的题目时一定要全面考虑啊!我们可以发现这个题的\(dp\)方程其实并不难想。
完结撒花!
//感谢rqy大佬qwqqq
#include<iostream>
#include<cstdio>
#define qwq register
using namespace std;
double p[10001],f[2001][2001],dp[2001][2001][2];
int a[2001][2001],c[20001],d[20001];
inline double min(double a,double b){
return a<b?a:b;
}
inline int qread(){
int k = 0;
char c;
c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c)){
k = (k<<1)+(k<<3)+c-48;
c = getchar();
}
return k ;
}
inline double qread_double()
{
double k=0;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c))k=k*10+(c-48),c=getchar();
if(c=='.')
{
double base=0.1;c=getchar();
while(isdigit(c))k=k+(c-48)*base,base/10,c=getchar();
}
return k;
}
int main()
{
int n,m,v,e,a1,b1,c1;
cin>>n>>m>>v>>e;
for(qwq int i=1;i<=n;i++)c[i]=qread();
for(qwq int i=1;i<=n;i++)d[i]=qread();
for(qwq int i=1;i<=n;i++)p[i]=qread_double();
for(qwq int i=1;i<=v;i++)
for(qwq int j=1;j<i;j++)
f[i][j]=f[j][i]=999999999;
for(qwq int i=1;i<=e;i++){
a1=qread(),b1=qread(),c1=qread();
f[a1][b1]=f[b1][a1]=min(f[a1][b1],c1);
}
for(qwq int k=1;k<=v;k++)
for(qwq int i=1;i<=v;i++)
for(qwq int j=1;j<i;j++)
if(f[i][k]+f[k][j]<f[i][j])
f[i][j]=f[j][i]=f[i][k]+f[k][j];
for(qwq int i=1;i<=n;i++)
for(qwq int j=0;j<=m;j++)
dp[i][j][0]=dp[i][j][1]=999999999;
dp[1][0][0]=dp[1][1][1]=0;
for(qwq int i=2;i<=n;i++){
double add1=f[c[i-1]][c[i]];
for(qwq int j=0;j<=min(m,i);j++)
{
dp[i][j][0]=min(dp[i-1][j][0]+add1,dp[i-1][j][1]+f[d[i-1]][c[i]]*p[i-1]+f[c[i-1]][c[i]]*(1-p[i-1]));
if(j!=0)
dp[i][j][1]=min(dp[i-1][j-1][0]+f[c[i-1]][d[i]]*p[i]+f[c[i-1]][c[i]]*(1-p[i]),dp[i-1][j-1][1]+f[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])+f[c[i-1]][d[i]]*(1-p[i-1])*p[i]+f[d[i-1]][c[i]]*(1-p[i])*p[i-1]+f[d[i-1]][d[i]]*p[i-1]*p[i]);
}
}
double hahaha=9999999999;
for(int i=0;i<=m;i++){
hahaha=min(dp[n][i][0],min(dp[n][i][1],hahaha));}
printf("%.2lf",hahaha);
}
\(By\) \(Flower\) _ \(pks\)
[NOIP2016]换教室(概率期望$DP$)的更多相关文章
- [NOIP2016]换教室 D1 T3 Floyed+期望DP
[NOIP2016]换教室 D1 T3 Description 对于刚上大学的牛牛来说, 他面临的第一个问题是如何根据实际情况中情合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第 ...
- bzoj4720: [Noip2016]换教室(期望dp)
4720: [Noip2016]换教室 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1294 Solved: 698[Submit][Status ...
- BZOJ 4720 [Noip2016]换教室
4720: [Noip2016]换教室 Description 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节课程安排在n个时间段上.在第i( ...
- 【BZOJ】4720: [Noip2016]换教室
4720: [Noip2016]换教室 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1690 Solved: 979[Submit][Status ...
- [NOIP2016]换教室 题解(奇怪的三种状态)
2558. [NOIP2016]换教室 [题目描述] 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第i(1< ...
- 【bzoj4720】[NOIP2016]换教室 期望dp
题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节课程安排在n个时间段上.在第i(1≤i≤n)个时间段上,两节内容相同的课程同时在不同的 ...
- 「NOIP2016」「P1850」 换教室(期望dp
题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 2n2n 节课程安排在 nn 个时间段上.在第 ii(1 \leq i \leq n1≤ ...
- 【bzoj4720】[NOIP2016]换教室
题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程.在可以选择的课程中,有2n节课程安排在n个时间段上.在第i(1≤i≤n)个时间段上,两节内容相同的课程同时在不同的 ...
- [NOIp2016] 换教室
题目类型:期望\(DP\) 传送门:>Here< 题意:现有\(N\)个时间段,每个时间段上一节课.如果不申请换教室,那么时间段\(i\)必须去教室\(c[i]\)上课,如果申请换课成功, ...
随机推荐
- ThreadPoolExecutor线程池中线程不能超过核心线程数量的问题
int arg1=2;//核心线程 int arg2=40;//最大线程数量 int arg3=100;//空余保留时间 ThreadPoolExecutor pool=new ThreadPoolE ...
- 关于JAVA项目报表选型过程
本人一直在走.NET技术路线,考虑到后期公司搞JAVA项目,也算是进行技术灾备,开始对JAVA技术进行关注.万事开头难,也是上来一头包.没办法,顶着上吧.上面开始分给我任务了.就是对后期项目报表进行方 ...
- java设计模式-----9、观察者模式
Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态. Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对 ...
- jquery each遍历判断返回false方法
在jquery each中遍历返回false失效,解决办法,用变量解决: var num = 0; $(".box").find("input[type='text']& ...
- Thymeleaf学习记录(7)--页面引入/片段引入
1.为页面添加footer: Templates文件夹下新建HTML文件: <!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xh ...
- WinFrom折线图
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- axios使用初涉
看vue的时候,vue2.0推荐使用axios做http请求,今天就学一下axios基本使用. 安装 axios 推荐npm方法(npm是node.js环境下的包管理器): npm install a ...
- arcgis 3种方法快速制作tpk文件(转)
来自:http://blog.csdn.net/arcgis_mobile/article/details/8048549 tpk是ArcGIS10.1推出的一种新的数据文件类型,主要是用于将切片文件 ...
- 12 步 30 分钟,完成用户管理的 CURD 应用 (react+dva+antd)
Getting Started https://github.com/dvajs/dva/blob/master/docs/GettingStarted.md -------------------- ...
- svn提示out of date的解决方法
步骤1. team–>update 步骤2. team–>Show Tree Conflict–>标记"冲突已解决" 步骤3. team–>commit