NOIP2016 换教室 期望DP
来源:互联网 发布:阿里弹性云 编辑:程序博客网 时间:2024/05/16 06:09
Problem
嗯,NOIP历年真题什么的,到处都有,抓一道就是三四倍经验题,我就不写题目描述了23333 偷个懒一定不会被人发现的
Solution
Thoughts
事实上,这是我第一次做概率与期望DP的题目,不是很懂套路,然后就想了很久很久,没什么太多的头绪。首先我觉得应该是用f[i][j]保存前i个时间段,申请换j次课,期望收获到的疲劳值。但是注意到这样的状态还是很复杂难以转移,因为状态转移后的状态有两种可能性,他有可能停在c[i]教室,也有可能停在d[i]教室。
可以联想到 [uva-1336修缮长城] 的那道题,通常为了避免复杂状态,我们通过加维来解决。所以用f[i][j][0]保存上次未申请的期望疲劳值,f[i][j][1]表示上次申请的期望疲劳值。但是状态转移方程有点让我纠结。
题外话
在dp的时候,就需要乘上事件发生的概率,我一直在纠结的是,发现好像有些情况下只乘一个概率似乎少了点什么,纠结了很久,最后问了问旁边的dalao,果然如此。这是期望DP的套路啊。感觉吃枣药丸。
Solution
那么由上我想到的思路,就可以很快地得出dp方程,如下。为了让方程看起来好看一点,我们用cc表示从c[i-1]教室到c[i]教室的路径,用cd表示c[i-1]教室到d[i]教室的路径,dc,dd以此类推。
其次,注意到这里的对f[i-1]的调用,每次更新时都只有j,j-1对当前更新的j有影响,那么我们可以采用滚动数组的思想,将j倒叙循环,这样得到的方程可以大大降低空间复杂度。
另外,f[i][0][0]是需要特判的,它仅能从f[i-1][0][0]上转移过来,因此,也有
Code
#include <iostream>#include <cstring>#include <cstdio>#include <queue>using namespace std;struct data{ int v,w,nxt;}edge[180010];const int INF=0x3f3f3f3f;int n,m,v,e,p,head[310],c[2010],d[2010],dis[310][310];double ans=INF,k[2010],f[2010][2];bool inq[310];queue<int> q;template <typename Tp> inline void read(Tp &x){ x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}inline double fmin(double x,double y){return x<y?x:y;}inline void insert(int u,int v,int w){ edge[++p].v=v;edge[p].w=w; edge[p].nxt=head[u];head[u]=p; edge[++p].v=u;edge[p].w=w; edge[p].nxt=head[v];head[v]=p;}void input(){ read(n),read(m),read(v),read(e); int u,v,w; for(int i=1;i<=n;i++) read(c[i]); for(int i=1;i<=n;i++) read(d[i]); for(int i=1;i<=n;i++) scanf("%lf",&k[i]); for(int i=1;i<=e;i++) { read(u),read(v),read(w); if(u==v) continue; insert(u,v,w); }}void spfa(int u){ int x,y; memset(inq,0,sizeof(inq)); for(int i=1;i<=v;i++) dis[u][i]=INF; dis[u][u]=0; while(!q.empty()) q.pop(); q.push(u); inq[u]=true; while(!q.empty()) { x=q.front(); q.pop(); inq[x]=false; for(int i=head[x];i;i=edge[i].nxt) { y=edge[i].v; if(dis[u][y]>dis[u][x]+edge[i].w) { dis[u][y]=dis[u][x]+edge[i].w; if(!inq[y]) q.push(y),inq[y]=true; } } }}int main(){ int cc,cd,dc,dd; double t; input(); for(int i=1;i<=v;i++) spfa(i); for(int j=0;j<=m;j++) f[j][0]=f[j][1]=INF; f[0][0]=f[1][1]=0.0; for(int i=2;i<=n;i++) { cc=dis[c[i-1]][c[i]];cd=dis[c[i-1]][d[i]]; dc=dis[d[i-1]][c[i]];dd=dis[d[i-1]][d[i]]; for(int j=(i<m?i:m);j>=1;j--) { t=fmin(f[j][0]+cc,f[j][1]+k[i-1]*dc+(1.0-k[i-1])*cc);//上次不换/换了 f[j][1]=fmin(f[j-1][0]+k[i]*cd+(1.0-k[i])*cc,f[j-1][1]+dd*k[i-1]*k[i]+cd*(1.0-k[i-1])*k[i]+dc*k[i-1]*(1.0-k[i])+cc*(1.0-k[i-1])*(1.0-k[i]));//上次不换/换了 f[j][0]=t; } f[0][0]+=cc; } for(int j=0;j<=m;j++) { if(ans>f[j][0]) ans=f[j][0]; if(ans>f[j][1]) ans=f[j][1]; } printf("%.2lf\n",ans); return 0;}
- 【期望dp】NOIP2016换教室
- noip2016 换教室 期望+DP
- NOIP2016 换教室 期望DP
- 【BZOJ】4720 [Noip2016]换教室 期望DP
- BZOJ4720(NOIP2016)[换教室]题解--期望DP
- BZOJ 4720 [Noip2016]换教室 期望DP
- 【NOIP2016】换教室(期望dp)
- NOIP2016[换教室] 期望概率DP
- BZOJ 4720: [Noip2016]换教室 期望dp
- [BZOJ4720][NOIP2016]换教室-期望DP
- [noip2016]换教室---floyd+期望DP
- noip2016 d1t3 换教室 期望dp+floyd
- BZOJ 4720 [Noip2016]换教室 (Floyd + 期望dp)
- bzoj 4720: [Noip2016]换教室 期望dp+最短路
- 【期望DP+最短路】BZOJ4720 [NOIP2016]换教室
- BZOJ 4720 [Noip2016]换教室——期望DP
- bzoj4720 [NOIP2016] 换教室(期望概率DP)
- BZOJ4720 [Noip2016]换教室 解题报告【SPFA】【期望DP】
- 通过setxxx()和getxxx()方法对类中的私有成员变量进行赋值和访问
- JavaScript的typeof运算符的可能结果
- 【C++心路历程41】【体检】【贪心】【思路题】
- linux命令--tree显示文件目录结构
- Hibernate 半深入懒加载与懒加载代理类
- NOIP2016 换教室 期望DP
- 谷歌的天敌竟然是亚马逊?从开放 7-Mic 阵列授权说起 | 洞见
- 95后中专肄业生登上欧洲顶级安全会议舞台
- JavaWeb学习心得之JSP内置对象
- JS中的this关键字
- kotlin
- Boundary-Aware Fully Convolutional Network for Brain Tumor Segmentation论文理解
- redis打开外网访问端口
- android 关于shape和selector和layer-list的drawableXML