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

  1. for(qwq int k=1;k<=v;k++)
  2. for(qwq int i=1;i<=v;i++)
  3. for(qwq int j=1;j<i;j++)
  4. if(f[i][k]+f[k][j]<f[i][j])
  5. 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\)即如下:

  1. #define qwq register
  2. for(qwq int i=1;i<=n;i++)
  3. for(qwq int j=0;j<=m;j++)
  4. dp[i][j][0]=dp[i][j][1]=999999999;
  5. dp[1][0][0]=dp[1][1][1]=0;
  6. for(qwq int i=2;i<=n;i++){
  7. double dist1=f[c[i-1]][c[i]],dist2=f[d[i-1]][c[i]],dist3=f[c[i-1]][d[i]];
  8. for(qwq int j=0;j<=min(m,i);j++)
  9. {
  10. 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]));
  11. if(j!=0)
  12. 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]);
  13. }
  14. }

总结:遇到期望的题目时一定要全面考虑啊!我们可以发现这个题的\(dp\)方程其实并不难想。

完结撒花!

  1. //感谢rqy大佬qwqqq
  2. #include<iostream>
  3. #include<cstdio>
  4. #define qwq register
  5. using namespace std;
  6. double p[10001],f[2001][2001],dp[2001][2001][2];
  7. int a[2001][2001],c[20001],d[20001];
  8. inline double min(double a,double b){
  9. return a<b?a:b;
  10. }
  11. inline int qread(){
  12. int k = 0;
  13. char c;
  14. c = getchar();
  15. while(!isdigit(c))c = getchar();
  16. while(isdigit(c)){
  17. k = (k<<1)+(k<<3)+c-48;
  18. c = getchar();
  19. }
  20. return k ;
  21. }
  22. inline double qread_double()
  23. {
  24. double k=0;char c=getchar();
  25. while(!isdigit(c))c=getchar();
  26. while(isdigit(c))k=k*10+(c-48),c=getchar();
  27. if(c=='.')
  28. {
  29. double base=0.1;c=getchar();
  30. while(isdigit(c))k=k+(c-48)*base,base/10,c=getchar();
  31. }
  32. return k;
  33. }
  34. int main()
  35. {
  36. int n,m,v,e,a1,b1,c1;
  37. cin>>n>>m>>v>>e;
  38. for(qwq int i=1;i<=n;i++)c[i]=qread();
  39. for(qwq int i=1;i<=n;i++)d[i]=qread();
  40. for(qwq int i=1;i<=n;i++)p[i]=qread_double();
  41. for(qwq int i=1;i<=v;i++)
  42. for(qwq int j=1;j<i;j++)
  43. f[i][j]=f[j][i]=999999999;
  44. for(qwq int i=1;i<=e;i++){
  45. a1=qread(),b1=qread(),c1=qread();
  46. f[a1][b1]=f[b1][a1]=min(f[a1][b1],c1);
  47. }
  48. for(qwq int k=1;k<=v;k++)
  49. for(qwq int i=1;i<=v;i++)
  50. for(qwq int j=1;j<i;j++)
  51. if(f[i][k]+f[k][j]<f[i][j])
  52. f[i][j]=f[j][i]=f[i][k]+f[k][j];
  53. for(qwq int i=1;i<=n;i++)
  54. for(qwq int j=0;j<=m;j++)
  55. dp[i][j][0]=dp[i][j][1]=999999999;
  56. dp[1][0][0]=dp[1][1][1]=0;
  57. for(qwq int i=2;i<=n;i++){
  58. double add1=f[c[i-1]][c[i]];
  59. for(qwq int j=0;j<=min(m,i);j++)
  60. {
  61. 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]));
  62. if(j!=0)
  63. 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]);
  64. }
  65. }
  66. double hahaha=9999999999;
  67. for(int i=0;i<=m;i++){
  68. hahaha=min(dp[n][i][0],min(dp[n][i][1],hahaha));}
  69. printf("%.2lf",hahaha);
  70. }

\(By\) \(Flower\) _ \(pks\)

[NOIP2016]换教室(概率期望$DP$)的更多相关文章

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

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

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

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

  3. BZOJ 4720 [Noip2016]换教室

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

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

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

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

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

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

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

  7. 「NOIP2016」「P1850」 换教室(期望dp

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

  8. 【bzoj4720】[NOIP2016]换教室

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

  9. [NOIp2016] 换教室

    题目类型:期望\(DP\) 传送门:>Here< 题意:现有\(N\)个时间段,每个时间段上一节课.如果不申请换教室,那么时间段\(i\)必须去教室\(c[i]\)上课,如果申请换课成功, ...

随机推荐

  1. C# 进程通信-命名管道

    之前看wcf服务的时候看到wcf有支持管道通信协议,之前不知道,最近刚好有用到这个,这里写个简单实例 .net有已经封装好的pip通信的对象NamedPipeServerStream 和NamedPi ...

  2. RESTORE DATABASE命令还原SQLServer 2005 数据库

    --返回由备份集内包含的数据库和日志文件列表组成的结果集. --主要获得逻辑文件名 USE master RESTORE FILELISTONLY FROM DISK = 'g:\back.Bak' ...

  3. RN canvas画布大小之谜

    一.需求 在一个高640.宽360的canvas内画一些坐标点. 二.问题 坐标点只显示了一部分,剩下的点没显示(其坐标属于(640,360)区域). 三.原因 canvas默认的画布大小是高150, ...

  4. 【转载】MySQL数据库可以用任意ip连接访问的方法

    通过CMD命令行修改数据库表的一个字段的值,实现连接,访问. 第一步.找到MYSQL软件安装所在的bin目录: (1)cd\当前目录 (2)指定MYSQL安装的bin目录 (3)输入 -h local ...

  5. Python 关于bytes类方法对数字转换的误区, Json的重要性

    本文起源于一次犯错, 在发觉bytes()里面可以填数字, 转出来的也是bytes类型, 就心急把里面的东西decode出来. 结果为空.搞来搞去以为是命令不熟练事实上错在逻辑. a1 = bytes ...

  6. h5 简单拖放

    最新的HTML5标准为所有的html元素规定了一个draggable属性,它表明了元素是否可以拖动,默认情况下,图像,链接,选中的文字是可以拖动的,因为他们的draggable属性被自动设置为true ...

  7. Linux基础入门之网络属性配置

    Linux基础入门之网络属性配置 摘要 Linux网络属性配置,最根本的就是ip和子网掩码(netmask),子网掩码是用来让本地主机来判断通信目标是否是本地网络内主机的,从而采取不同的通信机制. L ...

  8. Sublime Text 3.1 3170正式版+Patch注册机

        Sublime Text 是一款轻量级的代码编辑器,也是HTML和散文先进的文本编辑器.Sublime Text 具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等. ...

  9. Ddos 反射性防护 simple

    加固NTP服务: 1.通过Iptables配置只允许信任的IP,访问本机的UDP的123端口,修改配置文件执行echo "disable monitor" >> /et ...

  10. Windows Azure系列公开课 - 第二课:为什么选择Windows Azure(上)

    Windows Azure是微软的云平台,可以提供广泛服务.您可以通过它搭建.部署并管理解决方案,用于实现您可以想象的几乎任何目标.换言之,WindowsAzure是拥有无限可能的世界.无论您是需要运 ...