https://www.luogu.org/problemnew/show/P1850
分析
先全部跑一边dij,把距离求出来
我们设f[i][j][0/1]表示第i个时段,用了j次换教室机会,当前教室有无使用机会的最小期望
$f[i+1][j][0]=min(f[i][j][0]+dis[c[i]][c[i+1]],f[i][j][1]+dis[c[i]][c[i+1]]*(1-p[i])+dis[d[i]][c[i+1]]*p[i])$
$f[i+1][j+1][1]=min(f[i][j][0]+dis[c[i]][c[i+1]*(1-p[i+1])+dis[c[i]][d[i+1]]*p[i+1],f[i][j][1]+dis[c[i]][c[i+1]]*(1-p[i])*(1-p[i])+dis[c[i]][d[i+1]]*(1-p[i])*p[i+1]+dis[d[i]][c[i+1]]*p[i]*(1-p[i+1])+dis[d[i]][d[i+1]]*p[i]*p[i+1]$
#include <iostream> #include <cstdio> #include <queue> #include <memory.h> using namespace std; const int N=2e3+10; struct Heap { int i,dis; friend bool operator < (Heap a,Heap b) { return a.dis>b.dis; } }; struct Graph { int v,w,nx; }g[2*90010]; int cnt,list[N]; int dis[N][N],c[N],d[N]; double f[N][N][2],p[N]; int n,m,v,e; void Add(int u,int v,int w) { g[++cnt]=(Graph){v,w,list[u]};list[u]=cnt; g[++cnt]=(Graph){u,w,list[v]};list[v]=cnt; } void Dij(int v0) { priority_queue<Heap> q; while (!q.empty()) q.pop(); q.push((Heap){v0,0});dis[v0][v0]=0; while (!q.empty()) { Heap a=q.top();q.pop(); int u=a.i,d=a.dis; if (dis[v0][u]<d) continue; for (int i=list[u];i;i=g[i].nx) if (dis[v0][g[i].v]>dis[v0][u]+g[i].w) dis[v0][g[i].v]=dis[v0][u]+g[i].w,q.push((Heap){g[i].v,dis[v0][g[i].v]}); } } int main() { 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",&p[i]); for (int i=1,u,v,w;i<=e;i++) scanf("%d%d%d",&u,&v,&w),Add(u,v,w); memset(dis,0x3f,sizeof dis); for (int i=0;i<=v;i++) dis[0][i]=0; for (int i=1;i<=v;i++) Dij(i); for (int i=0;i<=n;i++) for (int j=0;j<=m;j++) for (int k=0;k<2;k++) f[i][j][k]=2147483647; f[0][0][0]=f[0][0][1]=0; for (int i=0;i<n;i++) for (int j=0;j<=min(i,m);j++) { f[i+1][j][0]=min(f[i+1][j][0],f[i][j][0]+dis[c[i]][c[i+1]]); f[i+1][j][0]=min(f[i+1][j][0],f[i][j][1]+dis[c[i]][c[i+1]]*(1.0-p[i])+dis[d[i]][c[i+1]]*p[i]); if (j<=min(i,m-1)) f[i+1][j+1][1]=min(f[i+1][j+1][1],f[i][j][0]+dis[c[i]][c[i+1]]*(1.0-p[i+1])+ dis[c[i]][d[i+1]]*p[i+1]); if (j<=min(i,m-1)) f[i+1][j+1][1]=min(f[i+1][j+1][1],f[i][j][1]+dis[c[i]][c[i+1]]*(1.0-p[i])*(1.0-p[i+1])+ dis[c[i]][d[i+1]]*(1.0-p[i])*p[i+1]+dis[d[i]][c[i+1]]*p[i]*(1.0-p[i+1])+dis[d[i]][d[i+1]]*p[i]*p[i+1]); } double ans=2147483647; for (int i=0;i<=m;i++) for (int j=0;j<=min(1,i);j++) ans=min(ans,f[n][i][j]); printf("%.2lf",ans); }