题目链接:Click here
Solution:
概率与期望,首先就应该想到dp,dp的原则就是不行就加一维
那么我们就能想到\(f[i][j][0/1]\)表示现在是第\(i\)节课,已经申请了\(j\)次,\(0/1\)表示这节课有没有申请
因为是最短距离,所以我们要先跑一遍\(Floyd\)求出两点之间的最短距离
然后转移的话,比较麻烦,不过很好想,就不再赘述,具体见代码
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+1;
const int V=301;
int n,v,m,e;
double f[N][N][2],pr[N];
int dis[V][V],a[N],b[N];
double ans=1111111111;
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}int main(){
memset(dis,0x3f,sizeof(dis));
n=read(),m=read(),v=read(),e=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) b[i]=read();
for(int i=1;i<=n;i++) scanf("%lf",&pr[i]);
for(int i=1;i<=e;i++){
int x=read(),y=read();
int val=read();
if(val<dis[x][y]){
dis[x][y]=val;
dis[y][x]=val;
}
}
for(int k=1;k<=v;k++)
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
if(dis[i][k]+dis[k][j]<dis[i][j])
dis[i][j]=dis[i][k]+dis[k][j];
for(int i=1;i<=v;i++) dis[i][i]=0;
for(int i=2;i<=n;i++){
f[i][0][0]=f[i-1][0][0]+(double)dis[a[i-1]][a[i]];
for(int j=1;j<=min(i,m);j++){
f[i][j][0]=f[i][j][1]=1e10;
if(j<i){
f[i][j][0]=(f[i-1][j][0]+(double)dis[a[i-1]][a[i]]);
f[i][j][0]=min(f[i][j][0],(f[i-1][j][1]+(1.0-pr[i-1])*(double)dis[a[i-1]][a[i]]+pr[i-1]*(double)dis[b[i-1]][a[i]]));
}
f[i][j][1]=(f[i-1][j-1][0]+pr[i]*(double)dis[a[i-1]][b[i]]+(1-pr[i])*(double)dis[a[i-1]][a[i]]);
if(j==1) continue;
double tmp=f[i-1][j-1][1];tmp+=pr[i-1]*pr[i]*(double)dis[b[i-1]][b[i]];
tmp+=pr[i-1]*(1-pr[i])*(double)dis[b[i-1]][a[i]];tmp+=(1-pr[i-1])*pr[i]*(double)dis[a[i-1]][b[i]];
tmp+=(1-pr[i-1])*(1-pr[i])*(double)dis[a[i-1]][a[i]];f[i][j][1]=min(f[i][j][1],tmp);
}
}ans=f[n][0][0];
for(int i=1;i<=m;i++)
ans=min(ans,min(f[n][i][1],f[n][i][0]));
printf("%.2lf\n",ans);
return 0;
}