【NOIP2016提高】换教室题解——作为概率DP入门题

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83062422

题目:luogu1850.

题目大意:给定v个教室,教室之间有e条无向边边,保证连通.现在有n组教室,每组有一个被钦定的教室和一个可以替换的教室,现在给你m次替换教室的机会,以及当你打算替换掉一组教室时成功的概率,让你求最后依次经过你选择的教室的期望路径最小值.

我觉得我的题目大意好像解释得不是很清晰...

模拟赛考真题的时候由于我没有写过概率DP,然后一直调这道题调了3h,导致T2部分分一点都没拿...

现在突然发现自己列的状态貌似不太主流,然后写的方式又细节极多,而且还是在我迷了很久期望的定义的情况写的...

我们现在来详解这道题.

首先我在考场列的状态是f[i][j][k]表示到第i个时段,用掉了j次机会,是否成功换掉了第j组教室的期望.

这个状态实际上是错误的,因为这个状态它已知是否申请成功,而题目上说是一次性提交的,说明不知道是否申请成功.

然后我们会发现这个东西列出方程后细节比较多,我们换一种转态.

我们依然设状态f[i][j][k],但这是k表示的是否申请去换地j组教室.

那么容易列出方程:

扫描二维码关注公众号,回复: 3618996 查看本文章

\tiny f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],f[i-1][j][1]+dis[c[i-1]][c[i]]*(1-k[i-1])+dis[d[i-1]][c[i]]*k[i-1])

\tiny f[i][j][1]=min(f[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1-k[i])+dis[c[i-1]][d[i]]*k[i],f[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dis[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dis[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dis[d[i-1]][d[i]]*k[i-1]*k[i])

当i=j=0时是要特殊处理的,j>0时f[i][j][1]时没有意义的,所以要判断.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=2000,V=300,INF=1<<29;
int dis[V+9][V+9];
int c[N+9],d[N+9];
double k[N+9],f[N+9][N+9][2],ans=INF*1.0;
int n,m,v,e;
void floyd(){
  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]);
}
Abigail into(){
  scanf("%d%d%d%d",&n,&m,&v,&e);
  for (int i=1;i<=n;i++) scanf("%d",&c[i]);
  for (int i=1;i<=n;i++) scanf("%d",&d[i]);
  for (int i=1;i<=n;i++) scanf("%lf",&k[i]);
  for (int i=1;i<=v;i++)
    for (int j=1;j<=v;j++)
      if (i^j) dis[i][j]=INF;
  int x,y,z;
  for (int i=1;i<=e;i++){
    scanf("%d%d%d",&x,&y,&z);
    if (dis[x][y]<=z) continue;
    dis[x][y]=dis[y][x]=z;
  }
}
Abigail work(){
  floyd();
  for (int i=0;i<=n;i++)
    for (int j=0;j<=m;j++)
      f[i][j][0]=f[i][j][1]=INF*1.0;
  f[1][0][0]=0;f[1][1][1]=0;
  for (int i=2;i<=n;i++){
    f[i][0][0]=f[i-1][0][0]+dis[c[i-1]][c[i]];
    for (int j=1;j<=m;j++){
      f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+dis[c[i-1]][c[i]]);
      f[i][j][0]=min(f[i][j][0],f[i-1][j][1]+dis[c[i-1]][c[i]]*(1-k[i-1])+dis[d[i-1]][c[i]]*k[i-1]);
      if (j>0) f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1-k[i])+dis[c[i-1]][d[i]]*k[i]);
      if (j>0) f[i][j][1]=min(f[i][j][1],f[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+dis[c[i-1]][d[i]]*(1-k[i-1])*k[i]+dis[d[i-1]][c[i]]*k[i-1]*(1-k[i])+dis[d[i-1]][d[i]]*k[i-1]*k[i]);
    }
  }
  for (int i=0;i<=m;i++)
    ans=min(ans,min(f[n][i][0],f[n][i][1]));
}
Abigail outo(){
  printf("%.2lf\n",ans);
}
int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/83062422