Luogu_P1850 换教室
### DP+期望
题目链接题目好长啊,也化简不了
考虑DP
设\(f[i][j][0/1]\)为从\(1\)到\(i\)交换\(j\)个(不一定成功),当前换或者不换的耗费体力值的总和的期望
先用floyd把任意两点之间的距离求出
然后进行DP
分当前点选与不选进行分类
具体看注释
代码和注释如下:
#include<bits/stdc++.h> using namespace std; const int maxn=2010; int n,m,v,e; int ci[maxn],di[maxn]; double p[maxn],tu[500][500],f[maxn][maxn][2]; int main() { scanf("%d%d%d%d",&n,&m,&v,&e); for(int i=1;i<=n;i++) scanf("%d",&ci[i]); for(int i=1;i<=n;i++) scanf("%d",&di[i]); for(int i=1;i<=n;i++) scanf("%lf",&p[i]); for(int i=1;i<=v;i++) for(int j=1;j<=v;j++) tu[i][j]=0x3f3f3f3f; for(int i=1;i<=v;i++) tu[i][i]=0; for(int x,y,i=1;i<=e;i++){ double z;scanf("%d%d%lf",&x,&y,&z); tu[x][y]=min(tu[x][y],z);tu[y][x]=tu[x][y]; } for(int k=1;k<=v;k++) for(int i=1;i<=v;i++) for(int j=1;j<=v;j++) tu[i][j]=min(tu[i][j],tu[i][k]+tu[k][j]); for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int k=0;k<=1;k++) f[i][j][k]=0x3f3f3f3f; f[1][0][0]=0.0;f[1][1][1]=0.0; for(int i=2;i<=n;i++) for(int j=0;j<=m && j<=i;j++){ //这次不选 f[i][j][0]=min(f[i-1][j][0]+tu[ci[i-1]][ci[i]],//上一次没选 f[i-1][j][1]+tu[ci[i-1]][ci[i]]*(1.0-p[i-1])+tu[di[i-1]][ci[i]]*p[i-1]);//上一个选了 if(j>=1){ //这次选 f[i][j][1]=min(f[i-1][j-1][0]+tu[ci[i-1]][di[i]]*p[i]//上一次没选,这次成功了的期望 +tu[ci[i-1]][ci[i]]*(1.0-p[i]),//上次没选,这次没成功的期望 f[i-1][j-1][1]+tu[di[i-1]][di[i]]*p[i]*p[i-1]//上次选了,这两次都成功了 +tu[di[i-1]][ci[i]]*p[i-1]*(1.0-p[i])//上次选了,上一次成功,这次失败 +tu[ci[i-1]][di[i]]*(1.0-p[i-1])*p[i]//上次选了,上次失败,这次成功 +tu[ci[i-1]][ci[i]]*(1.0-p[i-1])*(1.0-p[i]));//上次选了,都失败 } } double ans=0x3f3f3f3f; for(int i=0;i<=m;i++) ans=min(ans,min(f[n][i][0],f[n][i][1])); printf("%.2lf",ans); return 0; }