其实吧我老早就把这题切了……因为说实话,这道题确实不难啊……李云龙:比他娘的状压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\)

转载于:https://www.cnblogs.com/pks-t/p/9357672.html

[NOIP2016]换教室(概率期望$DP$)相关推荐

  1. BZOJ 4720 [Noip2016]换教室

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

  2. luogu1850 [NOIp2016]换教室 (floyd+dp)

    首先floyd求出每两点间的距离(注意自己到自己的距离要设成0) 然后就是dp了 一开始照着Lifeguards的样子,钦定了一下i这个点一定要选,然后发现复杂度不对,还想了好长时间优化 然后一翻题解 ...

  3. 洛谷1850(NOIp2016) 换教室——期望dp

    题目:https://www.luogu.org/problemnew/show/P1850 状态里记录的是"上一回有没有申请",而不是"上一回申请成功否",不 ...

  4. noip2016 换教室

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

  5. Noip2016换教室

    传送门! Simple Description: 牛牛有$n$节课要上,每个时段都有$2$个教室在上课(具体来说是第$c[i]$与第$d[i]$个教室),牛牛在其中的一个教室上课,牛牛起初每节课分别被 ...

  6. BZOJ 4720: [Noip2016]换教室

    错是被学长挑出来的...QWQ@Monster_Yi f[i][j][0/1] 为 第i天,换j次,换1/没换0 然后大力DP #include<cstdio> #include<i ...

  7. P1850 [NOIP2016 提高组] 换教室

    P1850 [NOIP2016 提高组] 换教室 题意: 有2n个课安排在n个时间段上,每个时间段上都有两个一样的课同时在不同地方上,起初牛牛被所有课都被安排在Ci上课,另一节课在Di上课.牛牛现在想 ...

  8. 【NOIp2016 day1t3】换教室

    NOIP第一次考期望,着实吓一跳... 读入之后, 由于 n<=200 n <= 200 n,给我们建立了天然的 floyd f l o y d floyd的机会, 建完图之后,能够顺利的 ...

  9. 【DP】【期望】$P1850$换教室

    [DP][期望]\(P1850\)换教室 链接 题目描述 有 \(2n\) 节课程安排在$ n$ 个时间段上.在第 \(i\)(\(1 \leq i \leq n\))个时间段上,两节内容相同的课程同 ...

最新文章

  1. androidx FloatingActionButton 中间加载的图片显示黑色
  2. spring配置文件import标签中使用${}占位符获得配置文件的属性值
  3. shell字段拼接日期_shell 脚本字符串拼接
  4. (0.2)HarmonyOS鸿蒙开发工具DevEco Studio工程文件目录结构
  5. LeetCode 134. 加油站(贪心)
  6. java请编写公共类继承抽象类_(Java相关)怎么理解抽象类,继承和接口?
  7. 21 FI配置-财务会计-为非征税事务分配税务代码
  8. Zetcode GUI 教程
  9. brighthouse mysql_MySQL 数据库中的数据页合并-爱可生
  10. 输入一个数,打印一个三角形
  11. 传感器技术—湿敏电阻式传感器(学习笔记五)
  12. 台式机使用笔记本电脑上网解决办法。
  13. yocto sysroot说明
  14. 人工神经网络的发展现状,神经网络未来发展趋势
  15. Day2 QT常用基础类型(自用)
  16. [2022CISCN]ez_usb
  17. 【正则表达式并且关系】
  18. neo4j-neoclient-example之movies 推荐
  19. cocos2d-x之FPS的显示与屏蔽
  20. 成年人的世界没有什么容易,脱发除外

热门文章

  1. android computescroll_Android Scroller与computeScroll的调用机制关系
  2. @autowired失败_@Autowired的使用:推荐对构造函数进行注释
  3. microsoft visual c++全家桶_橡木桶——白兰地风味的“主宰”
  4. msp430单片机oled汉字字模_OLED液晶屏如何显示中文呢?
  5. 小程序开发好学吗?需要掌握哪些知识技能?
  6. python中字符串str的strip()方法
  7. 根据大小分割大文本_值得一看的文本检测方法
  8. Java教程:Java字符串替换实例
  9. 测试流程图_入职两年银行测试员经验总结:我是如何帮人们“避雷”的?
  10. php db类 应用实例,PHP封装类似thinkphp连贯操作数据库Db类与简单应用示例